在运行时通过 lambda 表达式获取局部变量(和参数)的名称 [英] Getting names of local variables (and parameters) at run-time through lambda expressions

查看:25
本文介绍了在运行时通过 lambda 表达式获取局部变量(和参数)的名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对在运行时以重构安全的方式检索局部变量(和参数)的名称感兴趣.我有以下扩展方法:

I’m interested in retrieving the names of local variables (and parameters) at run-time in a refactor-safe manner. I have the following extension method:

public static string GetVariableName<T>(Expression<Func<T>> variableAccessExpression)
{
    var memberExpression = variableAccessExpression.Body as MemberExpression;
    return memberExpression.Member.Name;
}

...返回通过 lambda 表达式捕获的变量的名称:

…which returns the name of the variable captured through a lambda expression:

static void Main(string[] args)
{
    Console.WriteLine(GetVariableName(() => args));
    // Output: "args"

    int num = 0;
    Console.WriteLine(GetVariableName(() => num));
    // Output: "num"
}

然而,这只是因为 C# 编译器将匿名函数中捕获的任何局部变量(和参数)提升为编译器生成的幕后类中的同名实例变量(根据 乔恩·斯基特).如果不是这种情况, 的演员阵容BodyMemberExpression 会失败,因为 MemberExpression 代表字段或属性访问.

However, this only works because the C# compiler promotes any local variables (and parameters) that are captured in anonymous functions to instance variables of the same name within a compiler-generated class behind the scenes (per Jon Skeet). If this were not the case, the cast of Body to MemberExpression would fail, since MemberExpression represents field or property access.

这个变量提升是记录在案的行为,还是其他版本的框架中可能发生变化的实现细节?

Is this variable promotion documented behaviour, or is it an implementation detail subject to change in other versions of the framework?

注意:这个问题是对我之前关于参数验证的问题的概括.

推荐答案

更新:这不再是 C# 6 的问题,它引入了 nameof 运算符来解决此类情况(请参阅 MSDN).

Update: This is no longer an issue from C# 6, which has introduced the nameof operator to address such scenarios (see MSDN).

我的问题的答案似乎是;该功能是非标准化的.情况似乎比我最初想象的还要暗淡.不仅捕获变量的提升是非标准化的,而且将匿名函数转换为它们的表达式树表示的整个规范也是如此.

It appears that the answer to my question is no; the feature is non-standardized. The situation seems even bleaker than I’d originally suspected; not only is the promotion of captured variables non-standardized, but so is the entire specification of converting anonymous functions to their expression tree representations.

这意味着即使是简单的匿名函数,例如下面的,也不能保证在框架的不同实现中产生一致的表达式树(直到转换标准化):

The implication of this is that even straightforward anonymous functions, such as the below, are not guaranteed to result in consistent expression trees across different implementations of the framework (until the conversion is standardized):

Expression<Func<int, int, int>> add = (int x, int y) => x + y;

以下摘录来自 C# 语言规范 4.0(强调在所有情况下添加).

The following excerpts are taken from the C# Language Specification 4.0 (emphasis added in all cases).

来自4.6 表达式树类型":

From "4.6 Expression tree types":

泛型类型Expression的确切定义以及匿名函数转换为表达式树类型时构造表达式树的精确规则,都在外本规范的范围,并在别处描述.

The exact definition of the generic type Expression<D> as well as the precise rules for constructing an expression tree when an anonymous function is converted to an expression tree type, are both outside the scope of this specification, and are described elsewhere.

来自6.5.2 匿名函数转换到表达式树类型的评估":

From "6.5.2 Evaluation of anonymous function conversions to expression tree types":

将匿名函数转换为表达式树类型会生成表达式树(第 4.6 节).更准确地说,匿名函数转换的评估导致构建一个对象结构,该结构表示匿名函数本身的结构.表达式树的精确结构以及创建它的确切过程是由实现定义的.

Conversion of an anonymous function to an expression tree type produces an expression tree (§4.6). More precisely, evaluation of the anonymous function conversion leads to the construction of an object structure that represents the structure of the anonymous function itself. The precise structure of the expression tree, as well as the exact process for creating it, are implementation defined.

6.5.3 实现示例"中的第三个示例演示了捕获局部变量的匿名函数的转换,并确认了我的问题中提到的变量提升:

The third example in "6.5.3 Implementation example" demonstrates the conversion of an anonymous function that captures a local variable, and confirms the variable promotion mentioned in my question:

局部变量的生命周期现在必须至少扩展到匿名函数委托的生命周期.这可以通过将局部变量提升"到编译器生成的类的字段中来实现.局部变量的实例化(第 7.15.5.2 节)则对应于创建编译器生成类的实例,并且访问局部变量对应于访问编译器生成类实例中的字段.

The lifetime of the local variable must now be extended to at least the lifetime of the anonymous function delegate. This can be achieved by "hoisting" the local variable into a field of a compiler generated class. Instantiation of the local variable (§7.15.5.2) then corresponds to creating an instance of the compiler generated class, and accessing the local variable corresponds to accessing a field in the instance of the compiler generated class.

本节末尾进一步证实了这一点:

This is further corroborated at the end of the section:

在将匿名函数转换为表达式树时,也可以使用这里应用的捕获局部变量的相同技术:对编译器生成的对象的引用可以存储在表达式树中,并且可以表示对局部变量的访问作为对这些对象的字段访问.这种方法的优点是它允许在委托和表达式树之间共享提升"的局部变量.

The same technique applied here to capture local variables can also be used when converting anonymous functions to expression trees: References to the compiler generated objects can be stored in the expression tree, and access to the local variables can be represented as field accesses on these objects. The advantage of this approach is that it allows the "lifted" local variables to be shared between delegates and expression trees.

但是,在该部分的开头有一个免责声明:

However, there is a disclaimer at the beginning of the section:

此处描述的实现基于 Microsoft C# 编译器使用的相同原则,但它绝不是强制实现,也不是唯一可能的实现.它只是简单地提到了到表达式树的转换,因为它们的确切语义超出了本规范的范围.

The implementation described here is based on the same principles used by the Microsoft C# compiler, but it is by no means a mandated implementation, nor is it the only one possible. It only briefly mentions conversions to expression trees, as their exact semantics are outside the scope of this specification.

附言Eric Lippert 在此评论中确认从未发布表达式树规范.DLR 下存在 Expression Trees v2 SpecCodePlex 上的文档,但其范围似乎并未涵盖匿名函数到 C# 中表达式树的转换.

P.S. Eric Lippert confirms in this comment that the expression tree specs were never shipped. There exists an Expression Trees v2 Spec under the DLR documentation on CodePlex, but its scope does not appear to cover the conversion of anonymous functions to expression trees in C#.

这篇关于在运行时通过 lambda 表达式获取局部变量(和参数)的名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆