【问题标题】:Can I get a method attribute from a generic delegate?我可以从通用委托中获取方法属性吗?
【发布时间】:2012-05-14 22:48:31
【问题描述】:

我确信论坛上的某个地方已经有答案了,但我至今没能找到它。根据this example,我将匿名方法与委托结合使用,以便使用具有不同参数但返回类型相同的不同方法都用作函数参数:

public delegate TestCaseResult Action();
...

[TestDescription("Test whether the target computer has teaming configured")]
public TestCaseResult TargetHasOneTeam()
{
  // do some logic here and return
  // TestCaseResult
}

[TestDescription("Test whether the target computer has the named team configured")]
public TestCaseResult TargetHasNamedTeam(string teamName)
{
  // do some logic here and return
  // TestCaseResult
}
...

public static void TestThat(TestCaseBase.Action action)
{
  TestCaseResult result = action.Invoke();

  // I want to get the value of the TestDescription attribute here
}
...

// usage
TestThat(() => TargetHasOneTeam());

TestThat(() => TargetHasNamedTeam("Adapter5"));

从示例中可以看出,我非常希望能够从 TestThat() 函数中获取 TestDescriptionAttribute 属性。我已经浏览了包含我的方法的 Action 参数,但无法“找到”我的 TargetHasOneTeam() 方法。

【问题讨论】:

  • 我认为这只有在您使用表达式时才有可能,例如。 System.Linq.Expressions.Expression<Action>。然后可以将body转换为MethodCallExpression,并使用里面的MethodInfo对象来查询属性...
  • 您的委托变成编译器生成的类,派生自 MulticastDelegate 之类的东西,其中包含您的方法信息。我认为可以通过反射得到它。
  • 我已经在类似的场景中试验过这种模式。我发现它非常脆弱。仅供参考。

标签: c# reflection delegates attributes


【解决方案1】:

如果您将 TestThat(() => TargetHasOneTeam())(将您的委托包装到另一个操作中)更改为 TestThat(TargetHasOneTeam) 并像这样更改 TestThat:

public static void TestThat(TestCaseBase.Action action)
{
  TestCaseResult result = action.Invoke();
  var attrs = action.GetInvocationList()[0].Method.GetCustomAttributes(true);

  // I want to get the value of the TestDescription attribute here
}

会给你你需要的。

用表达式:

public static void TestThat(Expression<Func<TestResult>> action)
{
    var attrs = ((MethodCallExpression)action.Body).Method.GetCustomAttributes(true);

    var result = action.Compile()();
}

【讨论】:

  • 如果 TargetHasOneTeam() 没有参数,我了解如何执行此操作,但如果我还想使用另一个函数执行此操作,例如 CheckTargetTeamName(string name),该怎么办?
  • 然后将您的 TestThat(...) 更改为 TestThat(Expression>) 或 TestThat(Expression>) 并遍历表达式树,如 @马特戴维建议。要调用真正的委托,您需要调用 expression.Compile() 并调用已编译的 lambda。
【解决方案2】:

在这种特殊情况下,它基本上是不可访问的。您正在创建一个执行相关方法的 lambda。该 lambda 最终会生成一个新方法,该方法最终是 Action 委托的参数。该方法与TargetHasOneTeam 无关,并且只有在您深入研究正文中的 IL 指令时才明显。

您可以跳过 lambda 并在此处进行方法组转换。

TestThat(TargetHasOneTeam);

现在TargetHasOneTeam 被直接分配给委托实例,并且在Delegate::MethodInfo 属性中可见。

注意:虽然这对于您遇到的问题来说通常是个坏主意。方法的属性不应影响其满足委托实例化的能力。如果可能的话,我会避免这种类型的检查。

【讨论】:

  • Val 解释了它是如何完成的,但我认为我同意你的观点,这似乎不是一个好主意,感谢您对幕后发生的事情的解释。
【解决方案3】:

您可以通过Attribute.GetCustomAttribute 获取任何成员的属性。首先检查该属性是否已定义。例如:

public static void TestThat(TestCaseBase.Action action)
{
    TestCaseResult result = action.Invoke();
    if(System.Attribute.IsDefined(action.Method, typeof(TestDescriptionAttribute)))
    {
        var attribute = (TestDescriptionAttribute)System.Attribute.GetCustomAttribute(action.Method,
            typeof(TestDescriptionAttribute));
        Console.WriteLine(attribute.TestDescription);
    }
}

【讨论】:

  • 如何帮助获取从委托的内部调用的方法的属性?
  • 为我的示例添加了一些细节;它不是从内部委托执行...
  • 我认为如果我没有将我的方法调用包装在匿名方法中,这个例子会起作用。 (如果我在下面使用 Val Bakhtin 的示例而不是我目前正在做的)
  • 您不需要将其包装在委托中,只需使用 TestThat(TargetHasOneTeam); 等。
【解决方案4】:

MSDN 上查看此示例。

class TestAuthorAttribute
{
  static void Test()
  {
    PrintAuthorInfo(typeof(FirstClass));
    PrintAuthorInfo(typeof(SecondClass));
    PrintAuthorInfo(typeof(ThirdClass));
  }

  private static void PrintAuthorInfo(System.Type t)
 {
    System.Console.WriteLine("Author information for {0}", t);

    // Using reflection.
    System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t);  // Reflection.

    // Displaying output.
    foreach (System.Attribute attr in attrs)
    {
        if (attr is Author)
        {
            Author a = (Author)attr;
            System.Console.WriteLine("   {0}, version {1:f}", a.GetName(), a.version);
        }
      }
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多