使用表达式获取方法的名称

我知道网站上有一些答案,如果这有任何重复,我道歉,但我发现的所有答案都没有做我想做的事情。

我正在尝试指定方法信息,因此我可以通过不使用字符串以类型安全的方式获取名称。 所以我试图用表达式提取它。

假设我想在此界面中获取方法的名称:

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

目前我可以使用THIS方法获取名称:

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

我可以调用helper方法如下:

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

但我正在寻找我可以获取方法名称而不指定参数的版本(null,null)

像这样:

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

但所有尝试都无法编译

有没有办法做到这一点?

 x => x.DoSomething 

为了使这个可编辑,我只看到两种方式:

  1. 转到非generics方式并将其参数指定为Action
  2. 自己指定Action作为目标委托类型: GetMethodInfo(x => new Action(x.DoSomething))

如果你可以使用第二个,它允许你省略参数,那么你可以编写你的GetMethodInfo方法,如下所示:

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

它适用于您的界面,但可能需要进行一些概括才能使其适用于任何方法,这取决于您。

以下与.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; } 

您可以将它与x => x.DoSomething这样的表达式x => x.DoSomething ,但是它需要一些包装到不同类型方法的generics方法中。

这是一个向后兼容的版本:

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

在Ideone上查看此示例代码 。 请注意,Ideone没有.NET 4.5。

这个问题是x.DoSomething代表一个方法组。 并且您必须以某种方式明确指定要将该方法组转换为哪种委托类型,以便可以选择该组的正确成员。 如果该组只包含一个成员并不重要。

编译器可能会推断出你的意思,但它并没有这样做。 (我认为就是这样,如果你添加该方法的另一个重载,你的代码就不会中断。)

Snowbear的回答包含对可能解决方案的良好建议。

这是一个旧问题的新答案,但回应了接受的答案的“冗长”投诉。 它需要更多代码,但结果是语法如下:

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

或者,对于具有返回值的方法

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

哪里

 object DoSomethingWithReturn(string param1, string param2); 

就像框架提供Action <>和Func <>委托最多16个参数一样,你必须有GetActionInfo和GetFuncInfo方法接受多达16个参数(或更多,尽管我认为如果你有16个方法,重构是明智的参数)。 代码更多,但语法有所改进。

如果您的应用程序允许依赖Moq (或类似的库),您可以执行以下操作:

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