使用反射获取将 Action<T> 作为其参数之一的方法
Use Reflection to Get a Method which Takes Action<T> as One of Its Parameters
具体来说,我正在查看一堆像这样重载的扩展方法(如果您猜不出来,它们是 SignalR 的一部分):
public static IDisposable On(this IHubProxy proxy, string eventName, Action onData);
public static IDisposable On<T>(this IHubProxy proxy, string eventName, Action<T> onData);
public static IDisposable On<T1, T2>(this IHubProxy proxy, string eventName, Action<T1, T2> onData);
现在,通过执行以下操作,我可以毫无问题地获取第一个(非通用)On 方法的 methodInfo:
var methodInfo = typeof(HubProxyExtensions).GetMethod("On", new[] {typeof(IHubProxy), typeof(string), typeof(Action)});
但是,我希望能够得到"On"方法的第二个或第三个定义。但是,我发现这样的事情 不 有效:
var methodInfo = typeof(HubProxyExtensions).GetMethod("On", new[] {typeof(IHubProxy), typeof(string), typeof(Action<>)});
在上述情况下,methodInfo 最终为空。有什么想法吗?
我认为没有办法使用您当前使用的方法来执行此操作。但是,通过获取所有方法然后使用 LINQ,您可以找到这样的方法:
var methodInfo = typeof(HubProxyExtensions).GetMethods().FirstOrDefault(x => x.Name == "On"
&& x.GetParameters().Count() == 3
&& x.GetParameters()[0].ParameterType == typeof(IHubProxy)
&& x.GetParameters()[1].ParameterType == typeof(string)
&& x.GetParameters()[2].ParameterType.IsGenericType
&& x.GetParameters()[2].ParameterType.GetGenericTypeDefinition() == typeof(Action<>));
(我知道 GetParameters()
有很多重复,但你明白了)
详细说明我的评论,我制作了这个自定义活页夹:
using System;
using System.Linq;
using System.Reflection;
public class GenericDefinitionBinder : Binder
{
public static readonly GenericDefinitionBinder Default = new GenericDefinitionBinder();
public override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
{
throw new NotImplementedException();
}
public override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
{
return match.SingleOrDefault(m => MethodOkay(m, types));
}
private static bool MethodOkay(MethodBase method, Type[] types)
{
var pars = method.GetParameters();
if(types.Length != pars.Length) return false;
for(int i = 0; i < types.Length; i++)
{
var par = pars[i].ParameterType;
if(!(par == types[i] || (par.IsGenericType && par.GetGenericTypeDefinition() == types[i])))
{
return false;
}
}
return true;
}
public override void ReorderArgumentArray(ref object[] args, object state)
{
throw new NotImplementedException();
}
public override object ChangeType(object value, Type type, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] names, out object state)
{
throw new NotImplementedException();
}
public override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
使用简单:
var methodInfo = typeof(HubProxyExtensions).GetMethod("On", BindingFlags.Public | BindingFlags.Static, GenericDefinitionBinder.Default, new[] {typeof(IHubProxy), typeof(string), typeof(Action<>)}, null);
要获取第二种方法的MethodInfo
,需要调用MakeGenericMethod
:
MethodInfo method = typeof(HubProxyExtensions).GetMethod("On");
MethodInfo generic = method.MakeGenericMethod(typeof(string));
并为要调用的 Action<T>
输入参数设置相同的 T
:
var onData = new Action<string>(Target);
generic.Invoke(this, new object[] { proxy, eventName, onData });
更新:抱歉,仅适用于 class 中的单个 On<T>
方法,没有第一个 (On
) 或第三个 (On<T1, T2>
) 方法。
具体来说,我正在查看一堆像这样重载的扩展方法(如果您猜不出来,它们是 SignalR 的一部分):
public static IDisposable On(this IHubProxy proxy, string eventName, Action onData);
public static IDisposable On<T>(this IHubProxy proxy, string eventName, Action<T> onData);
public static IDisposable On<T1, T2>(this IHubProxy proxy, string eventName, Action<T1, T2> onData);
现在,通过执行以下操作,我可以毫无问题地获取第一个(非通用)On 方法的 methodInfo:
var methodInfo = typeof(HubProxyExtensions).GetMethod("On", new[] {typeof(IHubProxy), typeof(string), typeof(Action)});
但是,我希望能够得到"On"方法的第二个或第三个定义。但是,我发现这样的事情 不 有效:
var methodInfo = typeof(HubProxyExtensions).GetMethod("On", new[] {typeof(IHubProxy), typeof(string), typeof(Action<>)});
在上述情况下,methodInfo 最终为空。有什么想法吗?
我认为没有办法使用您当前使用的方法来执行此操作。但是,通过获取所有方法然后使用 LINQ,您可以找到这样的方法:
var methodInfo = typeof(HubProxyExtensions).GetMethods().FirstOrDefault(x => x.Name == "On"
&& x.GetParameters().Count() == 3
&& x.GetParameters()[0].ParameterType == typeof(IHubProxy)
&& x.GetParameters()[1].ParameterType == typeof(string)
&& x.GetParameters()[2].ParameterType.IsGenericType
&& x.GetParameters()[2].ParameterType.GetGenericTypeDefinition() == typeof(Action<>));
(我知道 GetParameters()
有很多重复,但你明白了)
详细说明我的评论,我制作了这个自定义活页夹:
using System;
using System.Linq;
using System.Reflection;
public class GenericDefinitionBinder : Binder
{
public static readonly GenericDefinitionBinder Default = new GenericDefinitionBinder();
public override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
{
throw new NotImplementedException();
}
public override MethodBase SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
{
return match.SingleOrDefault(m => MethodOkay(m, types));
}
private static bool MethodOkay(MethodBase method, Type[] types)
{
var pars = method.GetParameters();
if(types.Length != pars.Length) return false;
for(int i = 0; i < types.Length; i++)
{
var par = pars[i].ParameterType;
if(!(par == types[i] || (par.IsGenericType && par.GetGenericTypeDefinition() == types[i])))
{
return false;
}
}
return true;
}
public override void ReorderArgumentArray(ref object[] args, object state)
{
throw new NotImplementedException();
}
public override object ChangeType(object value, Type type, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] names, out object state)
{
throw new NotImplementedException();
}
public override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
使用简单:
var methodInfo = typeof(HubProxyExtensions).GetMethod("On", BindingFlags.Public | BindingFlags.Static, GenericDefinitionBinder.Default, new[] {typeof(IHubProxy), typeof(string), typeof(Action<>)}, null);
要获取第二种方法的MethodInfo
,需要调用MakeGenericMethod
:
MethodInfo method = typeof(HubProxyExtensions).GetMethod("On");
MethodInfo generic = method.MakeGenericMethod(typeof(string));
并为要调用的 Action<T>
输入参数设置相同的 T
:
var onData = new Action<string>(Target);
generic.Invoke(this, new object[] { proxy, eventName, onData });
更新:抱歉,仅适用于 class 中的单个 On<T>
方法,没有第一个 (On
) 或第三个 (On<T1, T2>
) 方法。