views:

98

answers:

5
struct SomeStruct
{
    public int Num { get; set; }
}

class Program
{
    static Action action;

    static void Foo()
    {
        SomeStruct someStruct = new SomeStruct { Num = 5 };
        action = () => Console.WriteLine(someStruct.Num);
    }

    static void Main()
    {
        Foo();
        action.Invoke();
    }
}
  1. Is a copy of someStruct created when the lambda is created?
  2. Is a copy of someStruct created when Foo returns?
  3. Can I verify that copying doesn't occur? In C++ I'd implement the copy constructor and print from inside it.

Citations from the standard will be appreciated. Any relevant online articles as well.

+6  A: 

It won't be copied, it creates a closure. Basically it'll encapsulate the structure in one object instead of creating it on the stack.

If you want to be sure you can always use reflector, but there is no need for that, the behavior is explained on Raymond Chen blog.

AlbertEin
Only problem is you can't create a parameterless constructor for a struct.
Rory
Opps, sorry about that
AlbertEin
+6  A: 

There will be no copies. Lambdas capture variables, not values.

You can use Reflector to look at the compile code: the compiler will move the "someStruct" variable into a helper class.

private static void Foo()
{
    DisplayClass locals = new DisplayClass();
    locals.someStruct = new SomeStruct { Num = 5 };
    action = new Action(locals.b__1);
}
private sealed class DisplayClass
{
    // Fields
    public SomeStruct someStruct;

    // Methods
    public void b__1()
    {
        Console.WriteLine(this.someStruct.Num);
    }
}

Copying structures will never cause user-defined code to run, so you cannot really check it that way. Actually, the code will do a copy when assigning to the "someStruct" variable. It would do that even for local variables without any lambdas.

Daniel
A: 

No, it doesn't copy, for the same reason (compiler creates a behind the scenes class to hold the value) that a copy of other value types isn't created when you capture a variable in a lambda.

for example, if you do:

int i = 7;
Action a = () => Console.WriteLine("lambda i=" + i);
i++;
a(); //prints 8
Console.WriteLine("main i=" + i); //prints 8

the lambda shares the 'i' with the declaring scope. same thing will happen with your struct. you can do this as a test to prove that copying doesn't occur.

dan
+1  A: 

<begin self promotion>I blogged about this a while ago. http://crazorsharp.blogspot.com/2009/06/how-do-closures-captured-variables-work.html </end self promotion>

BFree
+3  A: 

See The implementation of anonymous methods in C# and its consequences (part 1). Your code is actually something like:

   class SomeHiddenClass {
     SomeStruct someStruct;
     someHiddenMethod() {
       Console.WriteLine(someStruct.Num);
     }
   }

   SomeHiddenClass someHiddenVar = new SomeHiddenClass();
   someHiddenVar.someStruct.Num = 5;
   action = someHiddenVar.someHiddenMethod;
Remus Rusanu
oops, hehe. +1 btw.
Will