如何 select 使用反射基于参数类型的方法?
How to select a method based on parameter types using reflection?
我有一个参数数组,我需要调用一个实例方法,该方法应该具有最适合调用的签名,并在我的参数数组中给出参数的数量和类型。我在 Whosebug 上的类似问题上很难找到答案,这是因为我所针对的方法没有任何具体名称;相反,我必须 select 来自用特定属性修饰的方法列表中的一个方法。
包含一些可以调用的方法的 class 示例:
public class TestClass
{
[MyAttribute]
public void DoStuff()
{
// Do something
}
[MyAttribute]
public void DoMoreStuff(string msg)
{
// Do something
}
[MyAttribute]
public void DoEvenMoreStuff(string msg, int count, bool isCool = true)
{
// Do Something
}
[MyAttribute]
public void DoEvenMoreStuff(object obj, int count, bool isCool = true)
{
// Do Something
}
}
现在,我需要能够调用用 MyAttribute
修饰的方法之一,但我事先不知道这些方法的名称。我只需要根据我已有的参数数组获取所有用 MyAttribute
和 select 装饰的方法;然后调用 selected 方法。
我应该怎么做才能select调用最好的方法?
我不确定我是否完全理解你,(如果我理解的话)你显然已经意识到严重缺陷这种方法有
但是,仅用于学术目的。你可以这样做
var argList = new object[] {"asd", 123, true };
var argTypes = argList.Select(x => x.GetType())
.ToList();
var testClass = new TestClass();
var method = testClass.GetType()
.GetMethods()
.Where(m => m.GetCustomAttributes(typeof(MyAttribute), false)
.Length > 0)
.FirstOrDefault(x => x.GetParameters()
.Select(y => y.ParameterType)
.SequenceEqual(argTypes));
if (method != null)
{
method.Invoke(testClass, argList);
}
如前所述,更好的方法是使用
Binder.SelectMethod Method (BindingFlags, MethodBase[], Type[], ParameterModifier[])
Selects a method from the given set of methods, based on the argument
type.
您可能想在默认活页夹 (Type.DefaultBinder
) 上使用 Binder.SelectMethod
。这将处理标准的隐式转换(例如到基本类型、接口或对象)以及一些数字转换(例如 int 到 double 和 long)。有关更详尽的描述,请参阅 documentation。这将不匹配 optional/default 参数。因此,如果您传递 string 和 int,它将不会与您示例中的第三个方法匹配,第三个布尔参数的默认值。请注意,您可能还想处理当可以选择多个候选方法时抛出的 AmbiguousMatchException。其使用的简短演示:
static void Main(string[] args)
{
var methods = typeof(TestClass).GetMethods()
.Where(mi => mi.GetCustomAttributes(true).OfType<MyAttribute>().Any()).ToArray();
var flags = BindingFlags.Default; // I did not see a difference with BindingFlags.OptionalParamBinding;
Type[][] cases = {
new Type[0],
new[] { typeof(string) },
new[] { typeof(string), typeof(int) },
new[] { typeof(string), typeof(int), typeof(bool) },
new[] { typeof(int), typeof(int), typeof(bool) }
};
foreach (var typeCase in cases)
{
string desc = "(" + string.Join(",", typeCase.Select(t => t?.Name ?? "<null>")) + ")";
var method = Type.DefaultBinder.SelectMethod(flags, methods, typeCase, null);
string result = method?.ToString() ?? "No matching method found";
Console.WriteLine($"{desc} -> {result}");
}
}
输出:
() -> Void DoStuff()
(String) -> Void DoMoreStuff(System.String)
(String,Int32) -> No matching method found
(String,Int32,Boolean) -> Void DoEvenMoreStuff(System.String, Int32, Boolean)
(Int32,Int32,Boolean) -> Void DoEvenMoreStuff(System.Object, Int32, Boolean)
我有一个参数数组,我需要调用一个实例方法,该方法应该具有最适合调用的签名,并在我的参数数组中给出参数的数量和类型。我在 Whosebug 上的类似问题上很难找到答案,这是因为我所针对的方法没有任何具体名称;相反,我必须 select 来自用特定属性修饰的方法列表中的一个方法。
包含一些可以调用的方法的 class 示例:
public class TestClass
{
[MyAttribute]
public void DoStuff()
{
// Do something
}
[MyAttribute]
public void DoMoreStuff(string msg)
{
// Do something
}
[MyAttribute]
public void DoEvenMoreStuff(string msg, int count, bool isCool = true)
{
// Do Something
}
[MyAttribute]
public void DoEvenMoreStuff(object obj, int count, bool isCool = true)
{
// Do Something
}
}
现在,我需要能够调用用 MyAttribute
修饰的方法之一,但我事先不知道这些方法的名称。我只需要根据我已有的参数数组获取所有用 MyAttribute
和 select 装饰的方法;然后调用 selected 方法。
我应该怎么做才能select调用最好的方法?
我不确定我是否完全理解你,(如果我理解的话)你显然已经意识到严重缺陷这种方法有
但是,仅用于学术目的。你可以这样做
var argList = new object[] {"asd", 123, true };
var argTypes = argList.Select(x => x.GetType())
.ToList();
var testClass = new TestClass();
var method = testClass.GetType()
.GetMethods()
.Where(m => m.GetCustomAttributes(typeof(MyAttribute), false)
.Length > 0)
.FirstOrDefault(x => x.GetParameters()
.Select(y => y.ParameterType)
.SequenceEqual(argTypes));
if (method != null)
{
method.Invoke(testClass, argList);
}
如前所述,更好的方法是使用
Binder.SelectMethod Method (BindingFlags, MethodBase[], Type[], ParameterModifier[])
Selects a method from the given set of methods, based on the argument type.
您可能想在默认活页夹 (Type.DefaultBinder
) 上使用 Binder.SelectMethod
。这将处理标准的隐式转换(例如到基本类型、接口或对象)以及一些数字转换(例如 int 到 double 和 long)。有关更详尽的描述,请参阅 documentation。这将不匹配 optional/default 参数。因此,如果您传递 string 和 int,它将不会与您示例中的第三个方法匹配,第三个布尔参数的默认值。请注意,您可能还想处理当可以选择多个候选方法时抛出的 AmbiguousMatchException。其使用的简短演示:
static void Main(string[] args)
{
var methods = typeof(TestClass).GetMethods()
.Where(mi => mi.GetCustomAttributes(true).OfType<MyAttribute>().Any()).ToArray();
var flags = BindingFlags.Default; // I did not see a difference with BindingFlags.OptionalParamBinding;
Type[][] cases = {
new Type[0],
new[] { typeof(string) },
new[] { typeof(string), typeof(int) },
new[] { typeof(string), typeof(int), typeof(bool) },
new[] { typeof(int), typeof(int), typeof(bool) }
};
foreach (var typeCase in cases)
{
string desc = "(" + string.Join(",", typeCase.Select(t => t?.Name ?? "<null>")) + ")";
var method = Type.DefaultBinder.SelectMethod(flags, methods, typeCase, null);
string result = method?.ToString() ?? "No matching method found";
Console.WriteLine($"{desc} -> {result}");
}
}
输出:
() -> Void DoStuff()
(String) -> Void DoMoreStuff(System.String)
(String,Int32) -> No matching method found
(String,Int32,Boolean) -> Void DoEvenMoreStuff(System.String, Int32, Boolean)
(Int32,Int32,Boolean) -> Void DoEvenMoreStuff(System.Object, Int32, Boolean)