使用表达式获取方法的名称
我知道网站上有一些答案,如果这有任何重复,我道歉,但我发现的所有答案都没有做我想做的事情。
我正在尝试指定方法信息,因此我可以通过不使用字符串以类型安全的方式获取名称。 所以我试图用表达式提取它。
假设我想在此界面中获取方法的名称:
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
为了使这个可编辑,我只看到两种方式:
- 转到非generics方式并将其参数指定为
Action
- 自己指定
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); }