我知道网站上有一些答案,如果这有任何重复,我道歉,但我找到的所有答案都没有做我想做的事。
我正在尝试指定方法信息,因此我可以通过不使用字符串以类型安全的方式获取名称。 所以我试图用表达式提取它。
假设我想在此界面中获取方法的名称:
public interface IMyInteface
{
void DoSomething(string param1, string param2);
}
目前我可以使用THIS方法获取名称:
MemberInfo GetMethodInfo<T>(Expression<Action<T>> expression)
{
return ((MethodCallExpression)expression.Body).Method;
}
我可以按如下方式调用辅助方法:
var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething(null, null));
Console.WriteLine(methodInfo.Name);
但是我正在寻找可以在不指定参数的情况下获取方法名称的版本(null,null)
像这样:var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething);
但所有尝试都无法编译
有办法做到这一点吗?
答案 0 :(得分:14)
x => x.DoSomething
为了使这个可编辑,我只看到两种方式:
Action<string, string>
Action<string, string>
作为目标代理类型:GetMethodInfo<IMyInteface>(x => new Action<string,string>(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;
}
它适用于您的界面,但可能需要进行一些概括才能使其适用于任何方法,这取决于您。
答案 1 :(得分:12)
以下与.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;
}
}
检查this sample code on Ideone。 请注意,Ideone没有.NET 4.5。
答案 2 :(得分:4)
问题在于x.DoSomething
表示方法组。并且您必须以某种方式明确指定要将该方法组转换为哪种委托类型,以便可以选择该组的正确成员。如果该组只包含一个成员,则无关紧要。
编译器可以推断你的意思是那个,但它没有那样做。 (我认为就是这样,如果你添加该方法的另一个重载,你的代码就不会破坏。)
Snowbear的回答包含对可能解决方案的良好建议。
答案 3 :(得分:2)
这是一个旧问题的新答案,但回应了接受答案的“冗长”投诉。它需要更多代码,但结果是语法如下:
MemberInfo info = GetActionInfo<IMyInterface, string, string>(x => x.DoSomething);
或者,对于具有返回值的方法
MemberInfo info = GetFuncInfo<IMyInterface, object, string, string>(x => x.DoSomethingWithReturn);
其中
object DoSomethingWithReturn(string param1, string param2);
就像框架提供Action&lt;&gt;和Func&lt;&gt;委托最多16个参数,你必须有GetActionInfo和GetFuncInfo方法接受多达16个参数(或更多,但我认为如果你有16个参数的方法,重构是明智的)。代码更多,但语法有所改进。
答案 4 :(得分:1)
如果您的应用程序允许依赖Moq(或类似的库),您可以执行以下操作:
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);
}
答案 5 :(得分:0)
如果可以使用nameof()
运算符,则可以使用以下方法。
好处之一是不必解开表达式树或提供默认值,也不必担心该方法具有该类型的非null实例。
// As extension method
public static string GetMethodName<T>(this T instance, Func<T, string> nameofMethod) where T : class
{
return nameofMethod(instance);
}
// As static method
public static string GetMethodName<T>(Func<T, string> nameofMethod) where T : class
{
return nameofMethod(default);
}
用法:
public class Car
{
public void Drive() { }
}
var car = new Car();
string methodName1 = car.GetMethodName(c => nameof(c.Drive));
var nullCar = new Car();
string methodName2 = nullCar.GetMethodName(c => nameof(c.Drive));
string methodName3 = GetMethodName<Car>(c => nameof(c.Drive));