2

I know a refactor safe way to get the name of a property with this answer. Is there a refactor safe way to get the name of a method?

I am using C# 5 and .Net 4.5.

To illustrate what I'm trying to do:

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. 
    } 
}
Community
  • 1
  • 1
Steven Wexler
  • 16,589
  • 8
  • 53
  • 80
  • What *exactly* are you trying to do, and which version of C# are you using? – Jon Skeet Jun 07 '13 at 06:04
  • I have two unit tests. UnitTestOne.cs and UnitTestTwo.cs. We've set up a framework based on naming conventions to store baselines in csv files: UnitTestOne.csv and UnitTestTwo.csv. These baselines are very related and have a lot of overlapping data. So, I'm trying to create a watchman test to check when unexpected data in these baselines diverge. The best way to get each of the baseline files is to call our `ReadTestCaseBaselines` which accepts a `Type` and a method name (well, more specifically a test case method name). – Steven Wexler Jun 07 '13 at 06:39
  • @JonSkeet I am using C# 5. – Steven Wexler Jun 07 '13 at 06:53
  • @SimonMourier I don't think my question is a duplicate because I am not specifically trying to get the name of the current method. In fact, I am really trying to get the name of a method that is neither the current method nor the calling method. – Steven Wexler Jun 07 '13 at 07:00
  • BTW UnitTestOne.cs and UnitTestTwo.cs should read `UnitTestOne` and `UnitTestTwo` in my comment above. It's late...sorry if that caused confusion! – Steven Wexler Jun 07 '13 at 07:23
  • I really don't understand how this question is a duplicate of http://stackoverflow.com/questions/2652460/c-sharp-how-to-get-the-name-of-the-current-method-from-code. That question asks how to get the name of the current method. This questions asks how to get the name of a method that is **not** the current method. Moreover, both require very different solutions because of this distinction. – Steven Wexler Jun 07 '13 at 07:42
  • I also do not think this is a duplicate of the listed question, and I would like to share a more flexible answer. – Ben Reich Jun 07 '13 at 16:13
  • That question only refers to getting the method name of the currently executing method, which is not exactly what this question is asking. Please reopen. – Ben Reich Jun 07 '13 at 16:28

2 Answers2

3

The simplest way is probably just to create a delegate for each method, and use the MulticastDelegate.Method property:

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);
    } 
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
3

UPDATE: Here is a nice post that explains and provides a flexible utility method to access MethodInfos with refactor safe code. http://www.codeducky.org/10-utilities-c-developers-should-know-part-two/


I think Jon Skeet's answer is fine if you only want to cover void parameterless methods. A more general solution would look like this:

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);
     }
}

Note that we use an array of Expression<Action<MyClass>> in order to make a list of method calls on MyClass without knowing the return type and parameter types of each method call. Each method call expression is provided dummy variables to instantiate the expression.

Then the body of each expression is cast to a MethodCallExpression which, as the type name indicates, holds an expression which is just the calling of a method. That type has a Method property which is the MethodInfo of the method being called.

In the link you provided, a property name is extracted similarly using a MemberExpression. Using MethodCallExpression makes the examples quite similar.

By the way, you can also use Expression<Action> instead of Expression<Action<MyClass>> if you prefer. Replace the methodCallExpressions instantiation with:

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

I see this as mostly a stylistic decision, although it would also allow you to encapsulate method calls on a different class, using something like () => (new MyClass2()).UnitTestThree().

Steven Wexler
  • 16,589
  • 8
  • 53
  • 80
Ben Reich
  • 16,222
  • 2
  • 38
  • 59