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

     2023-04-18     305

关键词:

【中文标题】使用表达式获取方法的名称【英文标题】:Get the name of a method using an expression 【发布时间】:2012-01-03 17:57:28 【问题描述】:

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

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

假设我想在这个接口中获取一个方法的名称:

public interface IMyInteface

    void DoSomething(string param1, string param2);

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

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

但是所有尝试都编译失败

有没有办法做到这一点?

【问题讨论】:

目前没有 VS,但我认为您应该尝试接受 DelegateAction&lt;string, string&gt; 在非通用替代方案中。在这种情况下,您应该能够传递一个方法组 如果我将输入更改为 Delegate,它将无法编译,并且错误是无法将方法组转换为委托。如果我将其更改为 Action 它似乎可以工作,但表达式被转换为 UnaryExpression 并且该方法为空,我无法看到从 UnaryExpression 获取它的位置 转换后..你试过var methodInfo = GetMethodInfo&lt;IMyInteface&gt;(DoSomething);而不是var methodInfo = GetMethodInfo&lt;IMyInteface&gt;(x =&gt; x.DoSomething);吗?另外,我仍然认为指定 (default(string), default(string)) - 更具可读性,并且在这种情况下您可以支持重载方法 我不能通过直接指定做某事来使用 GetMethodInfo(DoSomething) 我需要引用实例,但是没有实例,这就是为什么它必须是一个表达式,IMyInterface 从来没有实际调用过具体实例,但仅用于提取元数据。我不知道我是否有意义 非常接近:get-method-name-using-lambda-expression 【参考方案1】:
x => x.DoSomething

为了使其可编译,我只看到了两种方法:

    采用非通用方式并将其参数指定为Action&lt;string, string&gt; 自行指定 Action&lt;string, string&gt; 作为您的目标委托类型:GetMethodInfo&lt;IMyInteface&gt;(x =&gt; new Action&lt;string,string&gt;(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;
    

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

【讨论】:

我希望能少一些冗长的东西,但是,这很好用,谢谢。 我很好奇,我知道已经有 2 年了,所以我希望你仍然可以回答:有没有办法允许这样的语法:GetMethodInfo&lt;MyInterface&gt;(x =&gt; x.DoSomething); 关于这种方法的说明,这仅适用于 .NET 3.5 和 4.0,不适用于 4.5。在后一种情况下,方法调用表达式的表示方式不同,因此参数顺序也不同。在这种情况下,您必须这样做:var methodInfoExpression = (ConstantExpression)methodCallExpression.Object;。总的来说,我觉得这种方法太麻烦了。 @nawfal,表达式树由编译器生成。您的目标是哪个 .Net 版本并不重要。您可能的意思是 C#2012 编译器生成的表达式树与早期版本不同。 @nawfal C# 5.0 编译器的行为会因目标框架而异。如果我没看错的话,对于.Net 4.0,它会生成CallDelegate.CreateDelegate,而对于.Net 4.5,它是新的MethodInfo.CreateDelegate【参考方案2】:

以下与 .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 =&gt; 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。

【讨论】:

【参考方案3】:

这个问题是x.DoSomething 代表一个方法组。而且您必须以某种方式明确指定要将方法组转换为哪种委托类型,以便可以选择组的正确成员。该组是否仅包含一个成员也没关系。

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

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

【讨论】:

【参考方案4】:

这是对旧问题的新答案,但对已接受答案的“冗长”投诉作出回应。它需要更多代码,但结果是这样的语法:

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

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

【讨论】:

我希望不那么冗长意味着我可以做这样的事情:GetMethodInfo&lt;MyInterface&gt;(x =&gt; x.DoSomething);?不过,我对如何实施您的建议感到有些困惑。你能提供一个快速的代码示例吗? 不传递参数的唯一方法(据我所知)是在通用规范中包含参数类型 - 即 GetMethodInfo(x => x.做某事)。【参考方案5】:

如果您可以使用nameof() 运算符,您可以使用以下方法。

其中一个好处是不必解开表达式树或提供默认值或担心该方法的类型的非空实例。

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

【讨论】:

如果你能强制在参数中使用nameof(),而不是仅仅使用一个字符串。【参考方案6】:

如果您的应用程序允许依赖 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);

【讨论】:

-1,这给了你正在创建的中间匿名委托的句柄(传递给GetMethodInfo 方法),而不是你试图代表的实际成员的句柄( DoSomething). @nawful 原始发帖人要求输入字符串 Name,而不是原始 MethodInfo。我已经更新了我的示例以澄清。 我担心它是否仍然不能给出正确的结果。你测试过这个吗? 是的,我已经测试过了。 哦,好吧,我看错了,你的编辑是没有根据的:)。在某种程度上,这是一个比公认的解决方案更好的解决方案,所以 +1。但缺点是您需要一个T 实例才能按您的方式工作。不太确定哪个性能更高。感谢添加!

在 woocommerce 中使用表达式获取产品名称

】在woocommerce中使用表达式获取产品名称【英文标题】:Getproductnameusingexpressioninwoocommerce【发布时间】:2020-03-1106:34:52【问题描述】:我可以使用表达式order_id获取订单ID,如下图所示。是否有任何表达式可以让我像OrderId一样获... 查看详情

在 Bigquery 中使用正则表达式获取地址的街道名称和编号

】在Bigquery中使用正则表达式获取地址的街道名称和编号【英文标题】:GetthestreetnameandnumberofanaddressusingregularexpressionsinBigquery【发布时间】:2020-12-0720:14:31【问题描述】:我有一堆地址,它们看起来不太相似。例如,我可以有STRE... 查看详情

如何使用反射获取调用方法名称和类型? [复制]

】如何使用反射获取调用方法名称和类型?[复制]【英文标题】:HowdoIgetthecallingmethodnameandtypeusingreflection?[duplicate]【发布时间】:2011-03-0623:00:57【问题描述】:可能重复:HowcanIfindthemethodthatcalledthecurrentmethod?我想写一个方法来获... 查看详情

go的方法值和方法表达式用法(代码片段)

...详细清晰,经过几个示例自己总结了下这块的用法。方法表达式:说简单点,其实就是方法对象赋值给变量。这里有两种使用方式:1)方法值:隐式调用,struct实例获取方法对象2) 方法表达式:显示调用,struct类型获取方法对... 查看详情

XPath 表达式查找标签名称包含“名称”的元素

】XPath表达式查找标签名称包含“名称”的元素【英文标题】:XPathexpressiontofindelementswhosetagnamecontains\'Name\'【发布时间】:2013-02-0214:24:13【问题描述】:我是XPath的新手。我正在寻找一种方法来获取标签名称包含特定字符串的所... 查看详情

使用 lambda 表达式获取属性名称和类型

】使用lambda表达式获取属性名称和类型【英文标题】:Getpropertynameandtypeusinglambdaexpression【发布时间】:2010-09-2109:31:47【问题描述】:我正在尝试编写一个函数,该函数将使用如下语法提取属性名称和类型:privateclassSomeClassPublicst... 查看详情

如何使用表达式和/或反射获取常量名称?

】如何使用表达式和/或反射获取常量名称?【英文标题】:HowtogetaConstantNameusingExpressionsand/orreflection?【发布时间】:2013-10-1006:35:41【问题描述】:我写了下面的但“我”总是为空?publicstaticclassTest1publicconststringCampaignManager="This_C... 查看详情

从 lambda 表达式中获取属性名称*没有*对象实例

】从lambda表达式中获取属性名称*没有*对象实例【英文标题】:Getapropertynamefromalambdaexpression*without*anobjectinstance【发布时间】:2021-10-0802:38:41【问题描述】:Asp.netMVC在Html泛型类上引入了EditorFor方法。它允许您编写简洁地标识视图... 查看详情

如何在不使用 iOS7 弃用方法的情况下获取 AirPlay 设备名称

】如何在不使用iOS7弃用方法的情况下获取AirPlay设备名称【英文标题】:HowtogettheAirPlaydevicenamewithoutusingiOS7deprecatedmethods【发布时间】:2014-07-1812:54:07【问题描述】:我正在使用GetnameofAirPlaydeviceusingAVPlayer此处描述的方法来检索连... 查看详情

如何获取每个打开窗口的名称列表?

...o.findwindows.find_windows(title_re="*")但是使用*作为正则表达式会引发错误我试过win32gui:它有wi 查看详情

从剃刀获取控制器名称

...果我在这里:http://www.example.com/MyController/Index如何从Razor表达式中获取控制器名称MyController:@*Obviouslythisn 查看详情

java在一串中文中,怎么只拿机场或者港口的名字

...数据处理方法。下面是一些可能的实现方式:1.利用正则表达式进行匹配:针对中文,可以使用正则表达式来匹配机场或者港口的名称,例如匹配以“机场”或者“港口”结尾的词语。然后再筛选出符合要求的名称。2.利用分词... 查看详情

获取导致异常的表单名称、方法名称和更多详细信息

...【发布时间】:2014-01-1705:45:40【问题描述】:我正在尝试使用Program.cs文件中的以下代码来捕获未处理的异常。我正在尝试创建一个包含错误的所有必需信息的字符串。这样我就可以识别代码中发生错误的点。我的问题是有一种... 查看详情

如何从 HttpRequestMessage 中获取方法名称?

...】:我有如下处理程序,我想从Controller获取方法名称。使用varmethodName=request.Method;只返回“GET”或“POST”之类的方法类型。如何获取方法名称,例如。从\'http://local 查看详情

jmeter之正则表达式提取器应用

原文:https://www.cnblogs.com/tudou-22/p/9566894.html说到Jmeter正则表达式提取器的应用,就不得不说到关联。所谓关联,就是把应用中动态变化返回的数据获取到,把它保存为一个参数,提供给后面需要用到的地方进行使用。Jmeter中关联... 查看详情

java如何获取方法参数中的名称

参考技术A一、从注解中获取使用注解方式,我们需要自定义一个注解,在注解中指定参数名,然后通过反射机制,获取方法参数上的注解,从而获取到相应的注解信息。这里自定义的注解是Param,通过value参数指定参数名,定义... 查看详情

如何在txt文件中返回方法的内容

...:2022-01-1802:11:39【问题描述】:我正在尝试编写一个正则表达式来返回方法名称和以下方法名称之间的方法内容。我将进一步解析我正在提取的信息。我怎么做?到目前为止,我已经开始从方法名称中获取信息,但不知道如何让... 查看详情

Hibernate SQLQuery - 按名称获取对象

...我需要一个类似的方法来通过“名称”获取类别。我通过使用Hibernate完成了这些方法。如何修复我的第二种方法以按名称获取类别?我的源代码如下://Itworks@OverridepublicCategory 查看详情