【问题标题】:Use Reflection to Get a Method which Takes Action<T> as One of Its Parameters [duplicate]使用反射获取将 Action<T> 作为其参数之一的方法 [重复]
【发布时间】:2015-10-01 15:29:07
【问题描述】:

具体来说,我正在研究一堆像这样重载的扩展方法(如果你猜不到的话,它们是 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 最终为空。有什么想法吗?

【问题讨论】:

  • 它不起作用,因为你在寻找Action&lt;&gt;,而参数的类型是Action&lt;T1, T2&gt;。你需要一个自定义的Binder

标签: c# reflection


【解决方案1】:

详细说明我的评论,我制作了这个自定义活页夹:

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

【讨论】:

    【解决方案2】:

    我认为您目前使用的方法没有办法做到这一点。但是,通过获取所有方法,然后使用 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() 有很多重复,但你明白了)

    【讨论】:

      【解决方案3】:

      要获取第二种方法的MethodInfo,需要调用MakeGenericMethod

      MethodInfo method = typeof(HubProxyExtensions).GetMethod("On");
      MethodInfo generic = method.MakeGenericMethod(typeof(string));
      

      并为Action&lt;T&gt; 输入参数设置相同的T 以调用:

      var onData = new Action<string>(Target);    
      generic.Invoke(this, new object[] { proxy, eventName, onData });
      

      更新:抱歉,仅适用于类中没有第一个 (On) 或第三个 (On&lt;T1, T2&gt;) 方法的单个 On&lt;T&gt; 方法。

      【讨论】:

      • typeof(HubProxyExtensions).GetMethod("On") 将抛出 AmbiguousMatchException
      • @IllidanS4 谢谢,这是真的!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-28
      • 2010-10-03
      • 1970-01-01
      • 2012-10-04
      • 1970-01-01
      相关资源
      最近更新 更多