C# 为什么要将lambda表达式指定给私有字段?

C# 为什么要将lambda表达式指定给私有字段?,c#,lambda,csla,C#,Lambda,Csla,我在工作中看了一些代码,发现了一些我不熟悉的东西 这是我熟悉的全部财产: private int myVar; public int MyProperty { get { return myVar; } set { myVar = value; } } 但后来我看到(我记不清了)这个: 这是在使用CSLA的应用程序中发现的。使用lambda表达式作为变量(公共或私有)就像使用可以更改的函数一样 例如,我可以做这样的事情 var myFavoriteFunction = (x)

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

这是我熟悉的全部财产:

private int myVar;
public int MyProperty
{
    get { return myVar; }
    set { myVar = value; }
}
但后来我看到(我记不清了)这个:


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

使用lambda表达式作为变量(公共或私有)就像使用可以更改的函数一样

例如,我可以做这样的事情

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

//do some work
myFavoriteFunction(someobject)

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

myFavoriteFunction(someobject)
public int AgeInDogYears() => Age * 7;

在不知道正在查看的代码的情况下,您可能会认为这是一个单击处理程序,单击按钮时执行的函数可能会更改。(当然,单击处理程序也可以做不同的操作,但这不是重点)

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

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

私有表达式myVar=x=>x.Something

它们有无数的用途,一个典型的例子是避免必须“硬编码”成员名称,否则必须将这些名称键入字符串文本(编译器不检查这些文本,并且很难重构)

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

您还可以在实现中看到这一点,例如

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


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


您可以将该方法的主体编写为lambda表达式

饼干写了关于属性(或字段)选择器的文章。。。这些有两个用途:一个(他提到的那个)获取字段/属性的名称

怎么做

鉴于:

Expression<Func<Foo, int>> expression = x => x.Something;
正如其他人所写,在C#6.0中,由于
nameof()
(通常更快,因为它是在编译时完成的,而不是在运行时完成的)和C#5.0中由于
[CallerMemberName]
而部分无用

第二个用途是,通过将作为“getter”(给定对象返回某物值的函数)的
表达式
传递给方法,该方法可以“构建”一个“setter”

Func getter=expression.Compile();
var参数=Expression.parameter(Expression.ReturnType);
Action setter=Expression.Lambda(
Expression.Assign(Expression.Body,参数),
新[]{expression.Parameters[0],parameter}).Compile();
Foo-Foo=新的Foo();
setter(foo,5);//setter的使用示例
int值=getter(foo);//getter的使用示例

如果必须使用一次setter,这比使用直接反射要慢得多(因为必须构建
表达式
s,然后进行编译等等,并且在
表达式
的构建和编译(但不是使用)中使用反射)。但是如果您需要多次使用getter/setter,那么它会变得更快(如果您“缓存”它们),因为以这种方式构建的getter/setter的使用速度几乎与直接访问属性/字段的速度一样快(缓慢的部分是getter/setter的创建)

想要添加的是,字段和属性的类型不是上面示例中的int类型,而是自定义类型。上面的代码真的可以编译吗?您正在将匿名函数分配给int类型的变量?这似乎是不可能的。上面的代码只是为了说明我看到lambda被分配到了字段,这对我来说是陌生的。这看起来像C#6特性,但语法错误。最明显的是,这是一个轻量级依赖项感叹词,而不是(一个方法)与显式实现的接口您通常可以同样轻松地使用委托/
Func
——这只是将函数式编程转换为主流OOP的一个好主意。如果您想发现某个东西的名称,您可以将其编写为
表达式myVar
,谢谢xanatos。你说得对!我做了相应的修改。@bickets:C#6中引入
nameof
操作符之前,就有
[CallerMemberName]
自定义属性(随C#5引入)它允许使用一种性能更好的替代方法来检索属性名称,而不是基于
表达式的方法。@stackx
CallMemberName
具有特定且有限的用途。只有当你能把你想要的东西命名为调用另一个函数时,它才会起作用。如果您希望能够“描述”某个对象的某些属性/方法,那么这是行不通的class@Biscuits不,这完全是由编译器完成的。编译后,
nameof
[CallMemberName]
都被替换为“常量”字符串。第一行是错误的,因为编译器既不知道
x
的类型,也不知道委托的最终类型。把它写成:
Func myFav=x=>x.FirstFunction()
@xanatos是正确的-但这不是因为C#无法推断类型,而是因为它可能是一个
Func
表达式
-这是我们必须付出的代价,让LINQ工作得更顺利;)@CarstenKönig你部分是对的。。。它可以用
var myvar=()=>5
这样的东西来看到。错误是一样的。但是在您编写的内容中,我要补充一点,编译器甚至不知道要使用的委托的确切类型。在.NET中,没有具有相同签名的代理的等价性。因此,
Func
谓词
是“不同的”,而两者在返回类型上都有相同的签名。@xanatos有些.NET语言(几乎)不存在这个问题;)-应该写“.NET”和“will not”而不是“cannot”^^
public int AgeInDogYears() => Age * 7;
Expression<Func<Foo, int>> expression = x => x.Something;
string name = ((MemberExpression)expression.Body).Member.Name;
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