使用反射获取将操作<T>作为其参数之一的方法



具体来说,我正在研究一堆扩展方法,它们都是这样重载的(它们是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最终为null。什么好主意吗?

详细说明我的评论,我做了这个自定义绑定:

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);

我不认为有一种方法可以做到这一点与您正在使用的当前方法。然而,通过获取所有的方法,然后使用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(),但你知道的意思)

要获得第二个方法的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 });

更新:对不起,只适用于类中没有第一(On)或第三(On<T1, T2>)方法的单个On<T>方法。

相关内容

  • 没有找到相关文章

最新更新