获取具有任何签名的任何方法的MethodInfo(任何签名的委托)

时间:2013-01-15 00:48:28

标签: c# reflection delegates

我想编写一个方法来分析任何方法的自定义属性(包含任意数量的参数和任何返回类型),只知道方法信息。 此函数将检查方法是否具有特定属性。像这样:var tmp = methodInfo.GetCustomAttributes(typeof(LineItemAttribute),false);如果它有这样的属性它将执行它。我希望调用该函数真的很容易使用。因此,在示例中,我想要调用三种方法和方法GetMethodAttributes

class Test
{
      public static void Main()
      {
      }

      public void Test1(){}

      public void Test2(int a){}

      public void Test3(object a, string c, Boolean d);

      public void GetMethodAttributes(MethodInfo mi) {}
}

理想情况下,我想写类似的东西

public static void Main()
    {
        var t = new Test();
        GetMethodAttributes(t.Test1);
        GetMethodAttributes(t.Test2);
        GetMethodAttributes(t.Test3);
    }

我不想使用方法名称的字符串表示,因为方法名称可能会改变,如:

MethodInfo info = type.GetMethod(name);

我有任何选择吗?基本上我需要一种方法来使用具有不同sinatures的函数的委托

2 个答案:

答案 0 :(得分:3)

正如Chris Sinclair在上述评论中指出的那样;您可以使用委托而不使用反射或表达式树来获取MethodInfo。缺点是编译器无法推断泛型参数,因此您必须指定委托类型以匹配给定方法的签名,如下所示:

public class Test
{
    public static void Main()
    {
        var t = new Test();
        CheckMethodAttributes<Action>(t.Test1);
        CheckMethodAttributes<Action<int>>(t.Test2);
        CheckMethodAttributes<Action<object, string, bool>>(t.Test3);
    }

    public void Test1() { }

    public void Test2(int a) { }

    public void Test3(object a, string c, bool d) { }

    public static void CheckMethodAttributes<T>(T func)
    {
        MethodInfo method = new MethodOf<T>(func);

        // Example attribute check:
        var ignoreAttribute = method.GetAttribute<IgnoreAttribute>();
        if (ignoreAttribute != null)
        {
            // Do something here...
        }
    }
}

这使用两个实用程序类,MethodOf<T>用于从给定的MethodInfo中提取Delegate,并使用一些AttributeUtils来获取强类型的自定义属性检索:

public static class AttributeUtils
{
    public static bool HasAttribute<TAttribute>(this MemberInfo member, bool inherit = true)
        where TAttribute : Attribute
    {
        return member.IsDefined(typeof(TAttribute), inherit);
    }

    public static TAttribute GetAttribute<TAttribute>(this MemberInfo member, bool inherit = true)
        where TAttribute : Attribute
    {
        return member.GetAttributes<TAttribute>(inherit).FirstOrDefault();
    }

    public static IEnumerable<TAttribute> GetAttributes<TAttribute>(this MemberInfo member, bool inherit = true)
        where TAttribute : Attribute
    {
        return member.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>();
    }
}

public class MethodOf<T>
{
    public MethodOf(T func)
    {
        var del = func as Delegate;
        if (del == null) throw new ArgumentException("Cannot convert func to Delegate.", "func");

        Method = del.Method;
    }

    private MethodInfo Method { get; set; }

    public static implicit operator MethodOf<T>(T func)
    {
        return new MethodOf<T>(func);
    }

    public static implicit operator MethodInfo(MethodOf<T> methodOf)
    {
        return methodOf.Method;
    }
}

答案 1 :(得分:2)

您可以使用Expression Trees执行此类操作,您可以通过lambda表达式传递方法。但是,您仍然需要为参数传递存根值。有关此操作的一个很好的示例,请查看Moq的源代码,该代码广泛使用此模式来设置单元测试的模拟行为。请注意,设置这不是一件小事。如果您需要相对快速和肮脏的东西,最好的选择可能是使用良好的重构工具和/或自动化测试的字符串名称来帮助解决重命名问题。