Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么这两个函数不返回相同的值?_C#_Delegates_Extension Methods - Fatal编程技术网

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;