Obtener el nombre de un método usando una expresión

Sé que hay algunas respuestas en el sitio al respecto y me disculpo si esto se duplica de alguna manera, pero todas las que encontré no hacen lo que bash hacer.

Estoy tratando de especificar la información del método para que pueda obtener el nombre de una manera segura al no usar cadenas. Así que estoy tratando de extraerlo con una expresión.

Digamos que quiero obtener el nombre de un método en esta interfaz:

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

Actualmente puedo obtener el nombre usando ESTE método:

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

Puedo llamar al método de ayuda de la siguiente manera:

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

Pero estoy buscando la versión en la que pueda obtener el nombre del método sin especificar los parámetros (nulo, nulo)

Me gusta esto:

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

Pero todos los bashs no comstackn

¿Hay alguna forma de hacer esto?

 x => x.DoSomething 

Para hacer esto comstackble, veo solo dos formas:

  1. Vaya de forma no genérica y especifique su parámetro como Action
  2. Especifique Action como su tipo de delegado de destino por usted mismo: GetMethodInfo(x => new Action(x.DoSomething))

Si está de acuerdo con el segundo, que le permite omitir los argumentos, puede escribir su método GetMethodInfo siguiente manera:

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

Funciona para su interfaz, pero probablemente será necesario generalizarlo para que funcione con cualquier método, eso depende de usted.

Lo siguiente es compatible con .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; } 

Puede usarlo con expresiones como x => x.DoSomething , sin embargo, sería necesario x => x.DoSomething algunos métodos generics para diferentes tipos de métodos.

Aquí hay una versión compatible con versiones anteriores:

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

Verifique este código de muestra en Ideone . Tenga en cuenta que Ideone no tiene .NET 4.5.

El problema con esto es que x.DoSomething representa un grupo de métodos. Y tiene que especificar de forma explícita a qué tipo de delegado desea convertir ese grupo de métodos, para que se pueda seleccionar el miembro correcto del grupo. Y no importa si ese grupo contiene solo un miembro.

El comstackdor podría inferir que quieres decir eso, pero no hace eso. (Creo que es así para que su código no se rompa si agrega otra sobrecarga de ese método).

La respuesta de Snowbear contiene buenos consejos sobre posibles soluciones.

Esta es una nueva respuesta a una pregunta anterior, pero responde a la queja “prolija” de la respuesta aceptada. Requiere más código, pero el resultado es una syntax como:

 MemberInfo info = GetActionInfo(x => x.DoSomething); 

o, para métodos con un valor de retorno

 MemberInfo info = GetFuncInfo(x => x.DoSomethingWithReturn); 

dónde

 object DoSomethingWithReturn(string param1, string param2); 

Al igual que el marco proporciona a Action <> y Func <> delegates hasta 16 parámetros, debe tener los métodos GetActionInfo y GetFuncInfo que aceptan hasta 16 parámetros (o más, aunque creo que la refactorización es sabia si tiene métodos con 16 parámetros). Mucho más código, pero una mejora en la syntax.

Si su aplicación permitiría una dependencia en Moq (o una biblioteca similar), podría hacer algo como esto:

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