Lambda表达式的重构安全的ArgumentException(Lambda expression

2019-09-17 12:52发布

更新 :这不再是从C#6,它推出了一个问题nameof运营商来解决这样的场景(参见MSDN )。

:请参阅“ 通过lambda表达式在运行时局部变量(和参数)的入门名 ”对这个问题的概括,以及一些答案。

我喜欢用lambda表达式创建的重构安全实现的想法INotifyPropertyChanged接口,使用类似于提供代码埃里克·德Carufel 。

我与实施提供参数名称的类似实验ArgumentException在重构安全的方式(或其派生类)。

我已经定义用于执行以下方法效用null检查:

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;

MemberExpression代表“访问字段或属性”。 这是保证在正常工作INotifyPropertyChanged情况下,由于lambda表达式将是一个属性访问。

然而,在上述我的代码,lambda表达式是语义上的参数访问,而不是一个字段或属性的访问。 代码工作的唯一原因是,C#编译器促进了在匿名函数幕后编译器生成的类中捕捉到的实例变量的任何局部变量(和参数)。 这是通过证实乔恩斯基特 。

我的问题是:这种行为是在.NET规范中记录(促进捕获参数,以实例变量),或者是它只是实现的细节可以在可选的实施方式或框架的未来版本的变化? 具体而言,可能会有环境下parameterAccessExpression.Body is MemberExpression返回false

Answer 1:

闭包:正如您所说,对于参数的访问,C#编译器(是的,特别是编译器)创建一个包含实例字段来存储您拍摄的参数变量的值封闭类。 莫非这个变化与C#编译器的未来版本? 当然。 也许在C#的未来版本中,生成闭合的类将有随机命名的变量,因为该名称并没有真正在运行时关系。 此外,你的代码可能不适用于其他.NET语言。 你会发现,VB .NET从C#生成表达式树和封闭班略有不同,有时...

我不知道如果你目前的实施将对于结构,无论是工作(尽管我可能是错记忆......我想对付拳击的情况可能只适用于Expression<Func<T, object>> (读,请youself尝试)。

反正......这一切说... ...它在C#未来版本的变化? 可能不是。 如果是这样,你可以改变你的内部实现对可能处理它?

至于性能:请非常小心这里。 你已经表示,将是更有效地传递两个参数,这样你就不需要编译和评估拉姆达....只是要清楚,你在谈论一个15至30ms打到这里每次编译时间,评估。



文章来源: Lambda expressions for refactor-safe ArgumentException