为什么要将 lambda 表达式分配给私有字段?

Why assign lambda expression to private field?

我在工作中查看了一些代码,发现了一些我不熟悉的东西。

此处已满属性我熟悉:

private int myVar;
public int MyProperty
{
    get { return myVar; }
    set { myVar = value; }
}

但后来我看到了(我记不清了)这个:

private int myVar = x => x.Something;

这是在使用 CSLA 的应用程序中发现的。

将 lambda 表达式用作变量(public 或私有)就像使用可以更改的函数。

例如我可以做这样的事情

var myFavoriteFunction = (x) => x.FirstFunction();

//do some work
myFavoriteFunction(someobject)

//now change the function
myFavoriteFunction = (x) => x.SecondFunction();

myFavoriteFunction(someobject)

在不知道您正在查看的代码的情况下,您可能会认为这是一个点击处理程序,点击按钮时正在执行的功能可能会发生变化。 (当然,您也可以使用不同的点击处理程序,但这不是重点)

以这种方式使用表达式也称为 属性 选择器.

正确的语法实际上是这样的。

private Expression<Func<Foo, int>> myVar = x => x.Something;

这些有无数的用途,一个典型的例子是避免必须 "hard-code" 成员名称,否则必须将其键入为字符串文字(编译器仍未检查并证明难以重构)。

下面是这个例子的一个实际应用。

Implementing INotifyPropertyChanged - does a better way exist?

您还看到它在 Fluent interface implementations, such as Fluent NHibernate 中被大量使用。

然而,随着 C# 6 中 nameof() 表达式的出现,我们很快就会看到这种技术逐渐消失。

http://davefancher.com/2014/12/02/c-6-0-nameof-expressions/

您看到的与 属性 无关,它是委托分配。 (类型可能不是 int)

Func<int,int> doubleMyNumber = (i) => 2 * i;

这就像一个委托,写成一个匿名函数。更多信息在这里:https://msdn.microsoft.com/fr-fr/library/bb397687.aspx

在 C# 6 中,您将能够看到像这样更奇怪的符号

public int AgeInDogYears() => Age * 7;

您将能够将方法的主体编写为 lambda 表达式。 http://csharp.2000things.com/2014/11/03/1217-using-lambda-expressions-for-function-members/

Biscuits 写了关于 属性(或字段)选择器...这些有两种用途:一种(他所说的)获得 field/property 的名称。

怎么做?

鉴于:

Expression<Func<Foo, int>> expression = x => x.Something;

你做到了:

string name = ((MemberExpression)expression.Body).Member.Name;

正如其他人所写,在 C# 6.0 中,由于 nameof()(通常速度更快,因为它是在编译时而不是在运行时完成的),在 C# 6.0 中这将变得几乎无用,而在 C# 5.0 中部分无用,这要归功于[CallerMemberName].

第二个用途是,通过将 Expression<> 传递给方法,即 "getter"(给对象 returns 某物的值的函数),该方法可以 "build" 一个 "setter".

Func<Foo, int> getter = expression.Compile();

var parameter = Expression.Parameter(expression.ReturnType);

Action<Foo, int> setter = Expression.Lambda<Action<Foo, int>>(
    Expression.Assign(expression.Body, parameter ), 
    new[] { expression.Parameters[0], parameter }).Compile();

Foo foo = new Foo();
setter(foo, 5); // Example of use of the setter
int value = getter(foo); // Example of use of the getter

如果你必须使用一次 setter,这比直接使用反射要慢得多(因为 Expressions 必须构建,然后编译等等,并且在Expression 的构建和编译(但不在使用中)有反射的使用)。但是如果你需要多次使用 getter/setter,那么它会变得更快(如果你 "cache" 它们),因为使用这种方式构建的 getter/setter 几乎和直接访问 property/field(较慢的部分是创建 getter/setter)