Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the name of a method using an expression

I know there are a few answers on the site on this and i apologize if this is in any way duplicate, but all of the ones I found does not do what I am trying to do.

I am trying to specify method info so I can get the name in a type safe way by not using strings. So I am trying to extract it with an expression.

Say I want to get the name of a method 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 am looking for the version that I can get the method name without specifying the parameters (null, null)

like this:

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

But all attempts fail to compile

Is there a way to do this?

like image 919
Andre Avatar asked Nov 22 '11 10:11

Andre


People also ask

Can you have an expression in a method call?

A method call expression produces the pure value returned by the method; the type of this value is specified by the return type in the method declaration. But if the method has the return type void, the expression does not produce a value.

Is nameof compile time c#?

A nameof expression is evaluated at compile time and has no effect at run time.


3 Answers

x => x.DoSomething 

In order to make this compilable I see only two ways:

  1. Go non-generic way and specify it's parameter as Action<string, string>
  2. Specify Action<string, string> as your target delegate type by yourself: GetMethodInfo<IMyInteface>(x => new Action<string,string>(x.DoSomething))

if you are ok to go with second one, which allows you to omit arguments then 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 probably some generalization will be required to make this working with any method, that's up to you.

like image 63
Snowbear Avatar answered Sep 21 '22 12:09

Snowbear


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, however it would require some wrapping into generic methods for different types of methods.

Here is a backwards-compatible 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 this sample code on Ideone. Note, that Ideone does not have .NET 4.5.

like image 21
Kędrzu Avatar answered Sep 21 '22 12:09

Kędrzu


The problem with this is that x.DoSomething represents a method group. And you have to somehow explicitly specify what delegate type do you want to convert that method group into, so that the correct member of the group can be selected. And it doesn't matter if that group contains only one member.

The compiler could infer that you mean that one, but it doesn't do that. (I think it's this way so that your code won't break if you add another overload of that method.)

Snowbear's answer contains good advice on possible solutions.

like image 22
svick Avatar answered Sep 22 '22 12:09

svick