C# 为什么这两个函数不返回相同的值?
考虑这个代码片段,试着猜测C# 为什么这两个函数不返回相同的值?,c#,delegates,extension-methods,C#,Delegates,Extension Methods,考虑这个代码片段,试着猜测y1和y2的计算结果 static class Extensions { public static Func<T> AsDelegate<T>(this T value) { return () => value; } } class Program { static void Main(string[] args) { new Program(); }
y1
和y2
的计算结果
static class Extensions
{
public static Func<T> AsDelegate<T>(this T value)
{
return () => value;
}
}
class Program
{
static void Main(string[] args)
{
new Program();
}
Program()
{
double x = Math.PI;
Func<double> ff = x.AsDelegate();
Func<double> fg = () => x;
x = -Math.PI;
double y1 = ff(); // y1 = 3.141..
double y2 = fg(); // y2 = -3.141..
}
}
因此,这两个函数必须返回同一类的两个不同实例。有趣的是,考虑代码< > FF()>代码>,它引用了局部变量<代码> FoO ,但是<代码> fg-()/<代码>没有,它依赖于当前范围内的内容。
那么,当这两个委托被传递到代码中对foo
实例不可见的其他部分时会发生什么呢?不知何故,当扩展方法与委托相结合时,谁拥有什么信息(数据)的问题变得越来越不明确。()=>x
捕获x值。编译器创建特殊类来处理lambda或匿名委托,捕获lambda中使用的任何变量
例如,如果运行以下代码:
List<Func<int>> list = new List<Func<int>>();
for (int i = 0; i < 5; i++)
{
list.Add(() => i);
}
list.ForEach(function => Console.WriteLine(function()));
List List=新列表();
对于(int i=0;i<5;i++)
{
列表.添加(()=>i);
}
list.ForEach(function=>Console.WriteLine(function());
您将看到打印的数字是相同的。
AsDelegate
捕获变量value
(AsDelegate的参数),而()=>x
捕获变量x
。因此,如果更改x
的值,lambda表达式将返回不同的值。更改x
不会更改值
请参阅:您需要了解。另请参见。扩展方法在调用AsDelegate
时使用x
的值,而lambda表达式()=>x
捕获变量x
,因此在调用表达式时取x
的值(而不是定义时的值)。在AsDelegate中,我们捕获的是参数“value”。此argent的值在调用方法时作为变量值的副本,并且永远不会更改-因此我们看到原始对象
直接lambda捕获变量foo(不是变量的值-变量本身)-因此我们确实看到了这方面的变化
基本上,添加一个方法调用改变了被捕获的大腿。ff
捕获(绑定)到此行的x
值:
Func<double> ff = x.AsDelegate();
Func<double> fg = () => x;
因此,当x
的值更改时,ff
不受影响,但fg
会更改。第一个方法为给定函数创建一个新委托并将其存储。如果稍后覆盖foo,则不会触及新创建的委托
第二个是一个lambda表达式,它提升/*捕获*它的上下文,这意味着foo变量。lambda表达式提升的变量的所有更改都被该lambda表达式看到。严格地说,它捕获参数值;参数值最初是x的值,永远不会改变ed.一个微妙的区别…所以当调用function()时,它使用我当时拥有的任何值(在循环之外)?我认为i
的范围在循环结束时结束…嗯…它A:不绑定任何值(编译器生成捕获类实例除外),b:不严格绑定到“x”一点也不清楚-是的,但我认为由于这种简单性可能有点误导。(简单性是好的)@Marc-这是个难题。我想把重点放在它在用户看来的方式上,而不是深入到它的实现方式上。当然。事实上,我的评论主要是针对“长尾”的-这样,看到答案的人可以看到(无需向下滚动)答案还有一点。你的答案很好;p
Func<double> fg = () => x;