C# 使用表达式获取方法的名称
我知道在这个网站上有一些答案,我很抱歉,如果这是以任何方式重复,但我发现的所有这些都没有做我想做的 我正在尝试指定方法信息,以便通过不使用字符串以类型安全的方式获取名称。 所以我试图用一个表达式来提取它 假设我要获取此接口中方法的名称:C# 使用表达式获取方法的名称,c#,expression,lambda,C#,Expression,Lambda,我知道在这个网站上有一些答案,我很抱歉,如果这是以任何方式重复,但我发现的所有这些都没有做我想做的 我正在尝试指定方法信息,以便通过不使用字符串以类型安全的方式获取名称。 所以我试图用一个表达式来提取它 假设我要获取此接口中方法的名称: public interface IMyInteface { void DoSomething(string param1, string param2); } 目前,我可以使用以下方法获取名称: MemberInfo GetMethodInfo&l
public interface IMyInteface
{
void DoSomething(string param1, string param2);
}
目前,我可以使用以下方法获取名称:
MemberInfo GetMethodInfo<T>(Expression<Action<T>> expression)
{
return ((MethodCallExpression)expression.Body).Method;
}
MemberInfo GetMethodInfo(表达式)
{
返回((MethodCallExpression)表达式.Body);
}
我可以按如下方式调用helper方法:
var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething(null, null));
Console.WriteLine(methodInfo.Name);
var methodInfo=GetMethodInfo(x=>x.DoSomething(null,null));
Console.WriteLine(methodInfo.Name);
但是我正在寻找一个不需要指定参数就可以获得方法名的版本(null,null)
像这样:
var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething);
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);
}
var methodInfo=GetMethodInfo(x=>x.DoSomething);
但所有的尝试都失败了
有办法做到这一点吗?如果您的应用程序允许依赖于(或类似的库),您可以这样做:
var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething);
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);
}
类程序
{
静态void Main(字符串[]参数)
{
var methodName=GetMethodName(x=>newaction(x.DoSomething));
Console.WriteLine(方法名);
}
静态字符串GetMethodName(Func Func),其中T:class
{
// http://code.google.com/p/moq/
var moq=新模拟();
var del=函数调用(moq.Object);
返回del.Method.Name;
}
}
公共接口IMyInteface
{
void DoSomething(字符串参数1、字符串参数2);
}
为了使其可编译,我只看到两种方法:
Action
Action
作为目标代理类型:GetMethodInfo(x=>newaction(x.DoSomething))
GetMethodInfo
方法:
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;
}
MemberInfo GetMethodInfo(表达式)
{
var unaryExpression=(unaryExpression)expression.Body;
var methodCallExpression=(methodCallExpression)unaryExpression.Operator;
var methodInfoExpression=(ConstantExpression)methodCallExpression.Arguments.Last();
var methodInfo=(MemberInfo)methodInfoExpression.Value;
返回方法信息;
}
它适用于您的界面,但可能需要一些泛化才能使其适用于任何方法,这取决于您。问题在于
x.DoSomething
表示一个方法组。您必须以某种方式明确指定要将该方法组转换为哪种委托类型,以便选择组中正确的成员。如果该组只包含一个成员,这并不重要
编译器可以推断您的意思是那个,但它没有这样做。(我认为这样做是为了在添加该方法的另一个重载时代码不会中断。)
斯诺贝尔的回答包含了关于可能解决方案的好建议。这是对一个老问题的新回答,但回应了对已接受答案的“冗长”抱怨。它需要更多的代码,但结果是语法如下:
MemberInfo info = GetActionInfo<IMyInterface, string, string>(x => x.DoSomething);
就像框架提供最多16个参数的Action和Func委托一样,您必须拥有最多接受16个参数的GetActionInfo和GetFuncInfo方法(或者更多,尽管我认为如果您有16个参数的方法,重构是明智的)。更多代码,但语法有所改进。以下代码与.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
之类的表达式一起使用,但是对于不同类型的方法,它需要一些包装到泛型方法中
以下是向后兼容的版本:
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没有.NET 4.5。如果您同意使用
nameof()
运算符,则可以使用以下方法
好处之一是不必打开表达式树或提供默认值,也不必担心该方法具有该类型的非空实例
//作为扩展方法
公共静态字符串GetMethodName(此T实例,Func nameofMethod),其中T:class
{
返回方法的名称(实例);
}
//作为静态方法
公共静态字符串GetMethodName(Func nameofMethod),其中T:class
{
返回nameofMethod(默认值);
}
用法:
公车
{
公用无效驱动器(){}
}
var car=新车();
字符串methodName1=car.GetMethodName(c=>nameof(c.Drive));
var nullCar=新车();
字符串methodName2=nullCar.GetMethodName(c=>nameof(c.Drive));
字符串methodName3=GetMethodName(c=>nameof(c.Drive));
目前没有VS,但我认为您应该尝试接受非通用替代方案中的委托
或操作
。在这种情况下,您应该能够传递一个方法组,如果我将输入更改为Delegate,它将不会编译,错误是无法将方法组转换为Delegate。如果我将其更改为Action,它似乎可以工作,但是表达式被转换为一个UnaryExpression,并且该方法为null,我看不到在转换后从UnaryExpressionAffer中获取该值的位置。。您是否尝试过var methodInfo=GetMethodInfo(DoSomething)代码>而不是var methodInfo=GetMethodInfo(x=>x.DoSomething)代码>?另外,我仍然认为指定(default(string),default(string))-更具可读性,在这种情况下可以支持重载方法。我不能通过直接指定do something来使用GetMethodInfo(DoSomething)。我需要引用实例,但没有实例,这就是为什么它必须是表达式,IMyInterface实际上从来不会与具体实例一起调用,而只是为了提取metdatata。我不知道我做的每件事是否有意义
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;
}
}