C# 如何使用反射根据参数类型选择方法?
我有一个参数数组,需要调用一个实例方法,该方法应该具有最适合调用的签名,并给出参数数组中参数的数量和类型。对于StackOverflow上的类似问题,我很难找到答案,因为我针对的方法没有任何特定的名称;相反,我必须从用特定属性修饰的方法列表中选择一个方法 包含一些可以调用的方法的类的示例:C# 如何使用反射根据参数类型选择方法?,c#,.net,system.reflection,C#,.net,System.reflection,我有一个参数数组,需要调用一个实例方法,该方法应该具有最适合调用的签名,并给出参数数组中参数的数量和类型。对于StackOverflow上的类似问题,我很难找到答案,因为我针对的方法没有任何特定的名称;相反,我必须从用特定属性修饰的方法列表中选择一个方法 包含一些可以调用的方法的类的示例: public class TestClass { [MyAttribute] public void DoStuff() {
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
修饰的方法,并根据我已有的一系列参数选择其中一个;然后调用所选的方法
我该如何选择要调用的最佳方法?我不确定我是否完全理解您(如果我理解),您显然知道这种方法存在严重缺陷 但是,仅用于学术目的。你可以这样做
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
(Type.DefaultBinder
)。这将处理标准的隐式转换(例如到基类型、接口或对象)以及一些数字转换(例如int到double和long)。有关更详细的说明,请参阅。这与可选/默认参数不匹配。因此,如果您传递string和int,它将不会将示例中的第三个方法与第三个布尔参数的默认值相匹配。注意,您可能还希望处理当可以选择多个候选方法时引发的含糊不清的MatchException。其使用的简短演示:
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}");
}
}
static void Main(字符串[]args)
{
var methods=typeof(TestClass).GetMethods()
.Where(mi=>mi.GetCustomAttributes(true).OfType().Any()).ToArray();
var flags=BindingFlags.Default;//我没有看到BindingFlags.OptionalParamBinding有什么不同;
类型[][]案例={
新类型[0],
新[]{typeof(string)},
新[]{typeof(string),typeof(int)},
新[]{typeof(string)、typeof(int)、typeof(bool)},
新[]{typeof(int),typeof(int),typeof(bool)}
};
foreach(cases中的var typeCase)
{
string desc=“(“+string.Join”(,“,typeCase.Select(t=>t?.Name??))+”;
var method=Type.DefaultBinder.SelectMethod(标志、方法、typeCase、null);
字符串结果=方法?.ToString()??“未找到匹配的方法”;
WriteLine($“{desc}->{result}”);
}
}
输出:
()->Void DoStuff()(字符串)->Void-domorseuff(System.String)
(字符串,Int32)->未找到匹配的方法
(String,Int32,Boolean)->Void DoEvenMoreStuff(System.String,Int32,Boolean)
(Int32,Int32,Boolean)->Void DoEvenMoreStuff(System.Object,Int32,Boolean)
当您有两个相同类型的参数时会发生什么情况,如何选择哪个值位于哪个位置?使用
MyAttribute
查找方法应该很简单。除了参数类型之外,还有哪些标准可用于选择?如果评估确定了加权相等的方法,是否会优先考虑某些类型?类型继承会发生什么情况?例如,如果您有[string,short,bool]类型的参数,那么最后两个方法都可以调用。我认为您可能需要使用的是Binder。在默认的Binder上选择method
,它将选择具有某些隐式转换(例如int到long)的“最佳匹配”。您打算如何处理默认值?如果有多个方法是等效匹配,则会引发异常。基本上,它类似于重载的方法,但不考虑方法名。在本例中,方法的唯一性不是基于它的名称,而是基于修饰它的属性。它确实看起来像是Binder。选择方法是一种方法。我不知道班上有没有活页夹。我正在通过Type.DefaultBinder.SelectMethod
尝试使用它。因为SelectMethod
只接受一个MethodBase
数组,所以我可以使用类似MyType.GetType().GetMethods().Where(method=>!method.IsStatic&&method.GetCustomAttributes(true.Count()>0)的东西简单地获取一个方法数组
并将其与我的参数类型一起传递给SelectMethod
。@ASilva同意这似乎是一种更好的方法您的解决方案非常有效!这似乎是.NET默认的做法,因为我可以在MSDN上看到。我希望其他有同样需求的人能发现你的答案很有用,因为它对我也很有用。基本上,任何对Type.GetMethod
在默认情况下查找方法所做的工作不满意的人都会发现这种方法非常有用。非常感谢你!