Копирование выполняется при получении типа значения в лямбду?

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. Копия someStruct создается, когда лямбда создается?
  2. Копия someStruct создается, когда Foo возвращается?
  3. Я могу проверить, что копирование не происходит? В C++ я реализовал бы конструктора копии и распечатал бы из него.

Цитаты из стандарта будут цениться. Любые соответствующие статьи онлайн также.

8
задан Stefan Monov 30 December 2009 в 19:58
поделиться

5 ответов

Копий не будет. 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.

.
9
ответ дан 5 December 2019 в 08:52
поделиться

Это не будет скопировано, это создаст закрытие. В основном он инкапсулирует структуру в один объект вместо того, чтобы создавать ее на стеке.

Если вы хотите быть уверены, что всегда можете использовать рефлектор, но в этом нет необходимости, поведение объясняется на блоге Raymond Chen.

.
6
ответ дан 5 December 2019 в 08:52
поделиться

См. Реализация анонимных методов в C# и их последствия (часть 1) . На самом деле код имеет вид:

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

   SomeHiddenClass someHiddenVar = new SomeHiddenClass();
   someHiddenVar.someStruct.Num = 5;
   action = someHiddenVar.someHiddenMethod;
3
ответ дан 5 December 2019 в 08:52
поделиться

<начало саморекламы> Я недавно об этом писал в блоге. http://crazorsharp.blogspot.com/2009/06/how-do-closures-captured-variables-work.html

1
ответ дан 5 December 2019 в 08:52
поделиться

Нет, он не копирует, по той же самой причине (компилятор создает за кулисами класс для хранения значения), что и копия других типов значений не создается, когда вы захватываете переменную в лямбда.

например, если вы это делаете:

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

лямбда разделяет 'i' с декларирующей областью видимости. То же самое произойдет и с вашей структурой. Вы можете сделать это в качестве теста, чтобы доказать, что копирование не происходит.

0
ответ дан 5 December 2019 в 08:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: