【问题标题】:Get MethodInfo for any method with any signature (delegate for any signature)获取具有任何签名的任何方法的 MethodInfo(任何签名的委托)
【发布时间】:2013-01-15 00:48:27
【问题描述】:

我想编写一个方法来分析任何方法的自定义属性(具有任意数量的参数和任何返回类型),只知道方法信息。 此函数将检查方法是否具有特定属性。像这样: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);

我有什么选择吗?基本上我需要一种方法来为具有不同特征的函数使用委托

【问题讨论】:

  • GetMethodAttributes 是做什么的,什么也没返回,你希望GetMethodAttributes(t.Test1); 做什么?
  • 这个函数会检查方法是否有特定的属性。像这样: var tmp = methodInfo.GetCustomAttributes(typeof(LineItemAttribute),false); 如果它有这样的属性,它会执行它。
  • 假设public void Test3(object a, string c, Boolean d);有属性,不传入任何参数你将如何执行
  • 在 Eric Lippert 的博客中:In Foof We Trust: A Dialogue
  • 使用隐式运算符有一种非常简洁的方法,甚至适用于重载解决方案:stackoverflow.com/a/3472250/1269654 编辑:那里的示例使用静态方法,但它也适用于实例方法(不要'甚至不需要实例化实例,只需在编译时引用类型化的 null 值就可以了)

标签: c# reflection delegates


【解决方案1】:

正如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&lt;T&gt; 用于从给定的 Delegate 中提取 MethodInfo 和一些 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;
    }
}

【讨论】:

  • 我实现了类似的方法:调用DataDrivenTestRunner.RunTheMethod(new Action&lt;string, int&gt;(this.BopRsSingleColumnOneItemIncreasedFontDataDriven));方法签名:public static void RunTheMethod(Delegate delegateToRun)并获取方法信息:MethodInfo mi = delegateToRun.Method;
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-29
    • 1970-01-01
    相关资源
    最近更新 更多