为什么这两个函数没有返回相同的值?

ja7*_*a72 5 c# extension-methods delegates

请考虑此代码段并尝试猜测y1y2评估

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..

    }
}
Run Code Online (Sandbox Code Playgroud)

您可能会说-Aha- double是一个值类型,因此扩展方法返回的值是main 的副本x.但是,当您将上述内容更改为类的委托时,结果仍然不同.例:

class Foo
{
    public double x;
}
    Program()
    {
        Foo foo = new Foo() { x=1.0 };

        Func<Foo> ff = foo.AsDelegate();
        Func<Foo> fg = () => foo;

        foo = new Foo() { x = -1.0 };

        double y1 = ff().x;    // y1 = 1.0
        double y2 = fg().x;    // y2 = -1.0
    }
Run Code Online (Sandbox Code Playgroud)

因此,这两个函数必须返回同一个类的两个不同实例.有趣的是,考虑到ff()它带有对局部变量的引用foo,但fg()没有并且它依赖于当前范围内的内容.

那么当这两个代理被传递给代码的其他部分时,会发生什么foo呢?不知何故,当扩展方法与代表结合时,谁拥有什么信息(数据)变得越来越不清楚.

dtb*_*dtb 7

AsDelegate捕获变量value(参数AsDelegate),同时() => x捕获变量x.因此,如果更改值x,则lambda表达式将返回不同的值.改变x不会改变value.

请参阅:外部可变陷阱


Bev*_*van 3

ff捕获(绑定)到这一行的值:x

Func<double> ff = x.AsDelegate();
Run Code Online (Sandbox Code Playgroud)

相比之下,fg绑定到这一行的变量: x

Func<double> fg = () => x;
Run Code Online (Sandbox Code Playgroud)

所以,当值发生x变化时,ff不是不受影响,而是fg变化。