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();
}
}
Цитаты из стандарта будут цениться. Любые соответствующие статьи онлайн также.
Копий не будет. Lambdas захватывает переменные, а не значения.
Для просмотра кода компиляции можно использовать рефлектор: компилятор переместит переменную "someStruct" в вспомогательный класс.
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);
}
}
Копирование структур никогда не приведет к запуску пользовательского кода, поэтому проверить его таким образом нельзя. На самом деле, код сделает копию при присваивании переменной "someStruct". Это будет сделано даже для локальных переменных без lambdas.
.Это не будет скопировано, это создаст закрытие. В основном он инкапсулирует структуру в один объект вместо того, чтобы создавать ее на стеке.
Если вы хотите быть уверены, что всегда можете использовать рефлектор, но в этом нет необходимости, поведение объясняется на блоге Raymond Chen.
.См. Реализация анонимных методов в C# и их последствия (часть 1) . На самом деле код имеет вид:
class SomeHiddenClass {
SomeStruct someStruct;
someHiddenMethod() {
Console.WriteLine(someStruct.Num);
}
}
SomeHiddenClass someHiddenVar = new SomeHiddenClass();
someHiddenVar.someStruct.Num = 5;
action = someHiddenVar.someHiddenMethod;
<начало саморекламы> Я недавно об этом писал в блоге. http://crazorsharp.blogspot.com/2009/06/how-do-closures-captured-variables-work.html
Нет, он не копирует, по той же самой причине (компилятор создает за кулисами класс для хранения значения), что и копия других типов значений не создается, когда вы захватываете переменную в лямбда.
например, если вы это делаете:
int i = 7;
Action a = () => Console.WriteLine("lambda i=" + i);
i++;
a(); //prints 8
Console.WriteLine("main i=" + i); //prints 8
лямбда разделяет 'i' с декларирующей областью видимости. То же самое произойдет и с вашей структурой. Вы можете сделать это в качестве теста, чтобы доказать, что копирование не происходит.