重构安全方法来检索方法名称

时间:2013-06-07 05:56:34

标签: c# reflection methods

我知道使用this answer获取属性名称的重构安全方法。是否有重构安全的方法来获取方法的名称?

我正在使用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. 
    } 
}

2 个答案:

答案 0 :(得分: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);
    } 
}

答案 1 :(得分:3)

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


如果您只想覆盖无参数无效方法,我认为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上的方法调用列表,而不知道每个方法调用的返回类型和参数类型。每个方法调用表达式都提供虚拟变量来实例化表达式。

然后将每个表达式的主体强制转换为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()之类的方法将方法调用封装在不同的类上。