Update:从 C# 6 开始这不再是问题,C# 6 引入了nameof https://stackoverflow.com/questions/11063502/getting-names-of-local-variables-and-parameters-at-run-time-through-lambda-exp操作员来解决此类情况(请参阅MSDN https://msdn.microsoft.com/en-us/library/dn986596.aspx).
Note: 请参阅“通过 lambda 表达式在运行时获取局部变量(和参数)的名称 https://stackoverflow.com/questions/11063502/getting-names-of-local-variables-and-parameters-at-run-time-through-lambda-exp”这个问题的概括以及一些答案。
我喜欢使用 lambda 表达式来创建重构安全实现的想法INotifyPropertyChanged
接口,使用类似于提供的代码埃里克·德·卡鲁费尔 http://blog.decarufel.net/2009/07/how-to-use-inotifypropertychanged-type_22.html.
我正在尝试实现类似的方法来向ArgumentException
(或其派生类)以重构安全的方式。
我定义了以下实用方法来执行null
checks:
public static void CheckNotNull<T>(Expression<Func<T>> parameterAccessExpression)
{
Func<T> parameterAccess = parameterAccessExpression.Compile();
T parameterValue = parameterAccess();
CheckNotNull(parameterValue, parameterAccessExpression);
}
public static void CheckNotNull<T>(T parameterValue,
Expression<Func<T>> parameterAccessExpression)
{
if (parameterValue == null)
{
Expression bodyExpression = parameterAccessExpression.Body;
MemberExpression memberExpression = bodyExpression as MemberExpression;
string parameterName = memberExpression.Member.Name;
throw new ArgumentNullException(parameterName);
}
}
然后可以使用以下语法以重构安全的方式执行参数验证:
CheckNotNull(() => arg); // most concise
CheckNotNull(arg, () => args); // equivalent, but more efficient
我的担忧在于以下几行:
Expression bodyExpression = parameterAccessExpression.Body;
MemberExpression memberExpression = bodyExpression as MemberExpression;
A MemberExpression http://msdn.microsoft.com/en-us/library/system.linq.expressions.memberexpression.aspx表示“访问字段或属性”。它保证在INotifyPropertyChanged
这种情况,因为 lambda 表达式将是属性访问。
然而,在我上面的代码中,lambda 表达式在语义上是范围访问,而不是字段或属性访问。该代码有效的唯一原因是 C# 编译器将匿名函数中捕获的任何局部变量(和参数)提升为编译器生成的类中的实例变量。这得到了证实乔恩·斯基特 https://stackoverflow.com/a/7220792/1149773.
我的问题是:这种行为(将捕获的参数提升为实例变量)是否记录在 .NET 规范中,或者它只是一个可能在框架的替代实现或未来版本中更改的实现细节?具体来说,是否存在这样的环境:parameterAccessExpression.Body is MemberExpression
回报false
?