2

我知道使用此答案获取属性名称的重构安全方法。是否有一种重构安全的方法来获取方法的名称?

我正在使用 C# 5 和 .Net 4.5。

为了说明我正在尝试做的事情:

class MyClass
{
    public void UnitTestOne() { /* impl */ }
    public void UnitTestTwo() { /* impl */ }
    public void UnitTestThree() 
    {
        //I'd like to get the method names for UnitTestOne and UnitTestTwo here
        //in such a way that this code will raise a compile time error if either 
        //the UnitTestOne or UnitTestTwo method names changes. 
    } 
}
4

2 回答 2

3

最简单的方法可能只是为每个方法创建一个委托,并使用该MulticastDelegate.Method属性:

class MyClass
{
    public void UnitTestOne() { /* impl */ }
    public void UnitTestTwo() { /* impl */ }
    public void UnitTestThree() 
    {
        var actions = new Action[] { UnitTestOne, UnitTestTwo };
        var names = actions.Select(x => x.Method.Name);
    } 
}
于 2013-06-07T07:22:27.040 回答
3

更新:这是一篇很好的文章,它解释并提供了一种灵活的实用程序方法来使用重构安全代码访问 MethodInfos。 http://www.codeducky.org/10-utilities-c-developers-should-know-part-two/


如果您只想介绍 void 无参数方法,我认为 Jon Skeet 的回答很好。更通用的解决方案如下所示:

public class MyClass
{
     public void UnitTestOne(int i) { /* impl */ }
     public int UnitTestTwo() { /* impl */ }
     public void UnitTestThree()
     {
          var methodCallExpressions = new Expression<Action<MyClass>>[] { 
              mc => mc.UnitTestOne(default(int)), //Note that a dummy argument is provided
              mc => mc.UnitTestTwo() 
          };

          var names = methodCallExpressions.Select(mce => 
              ((MethodCallExpression) mce.Body).Method.Name);
     }
}

请注意,我们使用数组是Expression<Action<MyClass>>为了在MyClass不知道每个方法调用的返回类型和参数类型的情况下制作方法调用列表。每个方法调用表达式都提供了虚拟变量来实例化表达式。

然后每个表达式的主体被强制转换为 a MethodCallExpression,正如类型名称所指示的,它包含一个表达式,该表达式只是一个方法的调用。该类型有一个Method属性,它是MethodInfo被调用方法的属性。

在您提供的链接中,使用MemberExpression. 使用MethodCallExpression使示例非常相似。

顺便说一句,如果您愿意,也可以使用Expression<Action>代替。Expression<Action<MyClass>>methodCallExpressions实例化替换为:

var methodCallExpressions = new Expression<Action>[] { 
      () => this.UnitTestOne(default(int)),
      () => this.UnitTestTwo() 
};

我认为这主要是一个风格上的决定,尽管它也允许您将方法调用封装在不同的类上,使用类似() => (new MyClass2()).UnitTestThree().

于 2013-06-10T06:27:11.820 回答