Search code examples
c#delegatesextension-methods

Why do these two functions not return the same value?


Consider this code snippet and try to guess what y1 and y2 evaluate to

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

    }
}

You might say -Aha- double is a value type and so the value returned by the extension method is a copy of the main x. But when you change the above into delegates of classes the results are still different. Example:

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
    }

So the two functions must return two different instances of the same class. It is interesting to consider that ff() carries with it a reference to local variable foo, but fg() does not and it relies on what is in scope currently.

So what happens when these two delegates are passed on to other parts of the code which do not have visibility to foo instance? Somehow the question of who owns what information (data) is becoming less and less clear when extension methods are combined with delegates.


Solution

  • ff captures (binds) to the value of x at this line:

    Func<double> ff = x.AsDelegate();
    

    By contrast, fg binds to the variable x at this line:

    Func<double> fg = () => x;
    

    So, when the value of x changes, ff is unafected, but fg changes.