Get method name using expression

I know that there are several answers on this site, and I apologize if this is repeated to some extent, but all those that I found do not do what I am trying to do.

I am trying to provide method information so that I can get the name in a safe way without using strings. So I'm trying to extract it with an expression.

Let's say I want to get the method name in this interface:

public interface IMyInteface { void DoSomething(string param1, string param2); } 

Currently, I can get the name using THIS method:

  MemberInfo GetMethodInfo<T>(Expression<Action<T>> expression) { return ((MethodCallExpression)expression.Body).Method; } 

I can call the helper method as follows:

 var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething(null, null)); Console.WriteLine(methodInfo.Name); 

But I'm looking for a version in which I can get the method name without specifying parameters (null, null)

like this:

 var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething); 

But all attempts are not compiled

Is there any way to do this?

+25
c # lambda expression
Nov 22 '11 at 10:28
source share
6 answers
 x => x.DoSomething 

To make this compile, I see only two ways:

  • Go to the shared path and specify it as Action<string, string>
  • Specify Action<string, string> as the target delegation type yourself: GetMethodInfo<IMyInteface>(x => new Action<string,string>(x.DoSomething))

if you agree to go with the second, which allows you to skip the arguments, you can write your GetMethodInfo method as follows:

  MemberInfo GetMethodInfo<T>(Expression<Func<T, Delegate>> expression) { var unaryExpression = (UnaryExpression) expression.Body; var methodCallExpression = (MethodCallExpression) unaryExpression.Operand; var methodInfoExpression = (ConstantExpression) methodCallExpression.Arguments.Last(); var methodInfo = (MemberInfo) methodInfoExpression.Value; return methodInfo; } 

It works for your interface, but it will probably take some generalization to work with any method that suits you.

+14
Nov 22 2018-11-11T00:
source share

The following is compatible with .NET 4.5:

 public static string MethodName(LambdaExpression expression) { var unaryExpression = (UnaryExpression)expression.Body; var methodCallExpression = (MethodCallExpression)unaryExpression.Operand; var methodCallObject = (ConstantExpression)methodCallExpression.Object; var methodInfo = (MethodInfo)methodCallObject.Value; return methodInfo.Name; } 

You can use it with expressions like x => x.DoSomething , but this will require some packaging into common methods for different types of methods.

Here is the reverse version:

 private static bool IsNET45 = Type.GetType("System.Reflection.ReflectionContext", false) != null; public static string MethodName(LambdaExpression expression) { var unaryExpression = (UnaryExpression)expression.Body; var methodCallExpression = (MethodCallExpression)unaryExpression.Operand; if (IsNET45) { var methodCallObject = (ConstantExpression)methodCallExpression.Object; var methodInfo = (MethodInfo)methodCallObject.Value; return methodInfo.Name; } else { var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last(); var methodInfo = (MemberInfo)methodInfoExpression.Value; return methodInfo.Name; } } 

Check out this sample code on Ideone . Note that Ideone does not have .NET 4.5.

+12
Nov 17 '14 at 15:28
source share

The problem is that x.DoSomething represents a group of methods. And you must somehow explicitly indicate what type of delegate you want to convert to this group of methods so that you can select the correct member of the group. And it does not matter if this group contains only one member.

The compiler may conclude that you mean this, but it is not. (I think that your code will not break if you add another overload of this method.)

The snowboard answer contains helpful tips on possible solutions.

+4
Nov 22 2018-11-11T00:
source share

This is a new answer to the old question, but answers the "detailed" complaint of the accepted answer. This requires more code, but the result is syntax, for example:

 MemberInfo info = GetActionInfo<IMyInterface, string, string>(x => x.DoSomething); 

or, for methods with a return value

 MemberInfo info = GetFuncInfo<IMyInterface, object, string, string>(x => x.DoSomethingWithReturn); 

Where

 object DoSomethingWithReturn(string param1, string param2); 

As with Framework, Action <> and Func <> delegates up to 16 parameters, you should have GetActionInfo and GetFuncInfo methods that take up to 16 parameters (or more, although I think refactoring is reasonable if you have methods with 16 parameters). Much more code, but better syntax.

+2
Apr 21 '12 at 0:40
source share

If your application allows Moq dependency (or a similar library), you can do something like this:

 class Program { static void Main(string[] args) { var methodName = GetMethodName<IMyInteface>(x => new Action<string,string>(x.DoSomething)); Console.WriteLine(methodName); } static string GetMethodName<T>(Func<T, Delegate> func) where T : class { // http://code.google.com/p/moq/ var moq = new Mock<T>(); var del = func.Invoke(moq.Object); return del.Method.Name; } } public interface IMyInteface { void DoSomething(string param1, string param2); } 
+1
Nov 22 2018-11-11T00:
source share

If you are nameof() using the nameof() operator, you can use the following approach.

One advantage is that you do not need to expand the expression tree or specify default values ​​or worry about having a non-zero type instance with the method.

 // As extension method public static string GetMethodName<T>(this T instance, Func<T, string> nameofMethod) where T : class { return nameofMethod(instance); } // As static method public static string GetMethodName<T>(Func<T, string> nameofMethod) where T : class { return nameofMethod(default); } 

Using:

 public class Car { public void Drive() { } } var car = new Car(); string methodName1 = car.GetMethodName(c => nameof(c.Drive)); var nullCar = new Car(); string methodName2 = nullCar.GetMethodName(c => nameof(c.Drive)); string methodName3 = GetMethodName<Car>(c => nameof(c.Drive)); 
0
May 13 '19 at 16:32
source share



All Articles