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