mav*_*vnn 7 c# lambda closures
我们的代码库中的几个方法使用'MaybeObject',可以在结果可能已知时传递给函数,或者可能依赖于尚未执行的外部Web服务调用.例如,下面的属性可以具有指定的已知值,或者如果未指定并在异步调用完成后调用它将返回异步调用的结果.
private string _internalString;
public string stringProp
{
get
{
if (!string.IsNullOrEmpty(_internalString))
return _internalString;
return resultOfAsyncCallFromSomewhereElse;
}
set { _internalString = value; }
}
Run Code Online (Sandbox Code Playgroud)
显然,尝试在异步调用完成之前引用该属性会导致空引用异常,因此我们还有一个标志来检查该值是否可用.
问题是,在下面的代码中会创建lambda尝试和评估stringProp(可能还没有填充),或者是否会推迟评估直到调用结果Action(在检查异步操作完成后)?
public Action ExampleMethod(MaybeObject maybe)
{
return () => doSomethingWithString(maybe.stringProp);
}
Run Code Online (Sandbox Code Playgroud)
在C#中,所有将在执行时进行评估,因为C#lambda Closures不是真正的Closure,它能够在创建时解析捕获环境的状态.
() => doSomethingWithString(maybe.stringProp);
Run Code Online (Sandbox Code Playgroud)
这里甚至引用maybe可能为null,在执行委托之前你不会遇到像NullReferenceException这样的问题.这个技巧有时用于后期绑定值解析.
闭包在创建时保留对环境的引用(例如,到封闭范围中的局部变量的当前值),而通用匿名函数不需要这样做.
C#Closure细节概述 - C#中的匿名方法和闭包
根据Closure的定义,可以推断Closure在创建过程中会记住变量的值.但是在C#中,通过在堆上创建外部局部变量(在本例中为i)与匿名方法共享.这意味着在匿名方法中对它的任何更改都会更改原始值,并且在第二次调用该方法时,它将i的修改值设置为1(请参阅第二行输出).这导致许多人认为匿名方法实际上不是Closure,因为它的定义应该记住在创建Closure时变量的值而不是可修改的.
评估将推迟到调用结果操作为止。
委托引用的代码仅在显式调用委托本身时执行,无论委托本身是如何创建的。
例如,通过Action委托传递要执行的代码的这些方式都是等效的,并且doSomethingWithString只有在调用以下方法时才会执行该方法Action():
显式方法(.NET 1.1):
private MaybeObject maybe;
public Action ExampleMethod()
{
return new Action(DoSomethingWithMaybeObject);
}
private void DoSomethingWithMaybeObject()
{
doSomethingWithString(maybe.stringProp)
}
Run Code Online (Sandbox Code Playgroud)
匿名方法(.NET 2.0):
public Action ExampleMethod(MaybeObject maybe)
{
return delegate() { doSomethingWithString(maybe.stringProp) };
}
Run Code Online (Sandbox Code Playgroud)
拉姆达(.NET 3.5):
public Action ExampleMethod(MaybeObject maybe)
{
return () => doSomethingWithString(maybe.stringProp);
}
Run Code Online (Sandbox Code Playgroud)
也可以看看:
| 归档时间: |
|
| 查看次数: |
1204 次 |
| 最近记录: |