C # лямбда использовать локальную переменную - PullRequest
4 голосов
/ 23 сентября 2019
class Program
    {        
        static Action act = null;

        static void Main(string[] args)
        {
            Test();
            act();
            act();
            Test();
            act();
        }   

        static void Test()
        {
            int count = 0;

            if(act == null) act = () => Console.Write(++count + " ");
        }
    }  

результат : 1 2 3 почему?

если delete [if(act == null)] результат : 1 2 1

Ответы [ 3 ]

11 голосов
/ 23 сентября 2019

В настоящее время вы создаете только один экземпляр делегата.Это захватывает локальную переменную, которая была объявлена ​​в методе Test при первом вызове.

Эта локальная переменная фактически имеет увеличенное время жизни из-за делегата, который ее захватывает.Каждый раз, когда вы вызываете делегата, он увеличивает одну и ту же переменную.

Когда вы удаляете условие if (act == null), вы создаете новый делегат при каждом вызове Test, что означает, что он захватывает другую countлокальная переменная, начиная с 0 каждый раз.Вы вызываете Test() дважды, и делегат, созданный посредством первого вызова, вызывается дважды (с выводом 1, затем 2).Создание делегата через второй вызов вызывается только один раз (с выводом 1).

3 голосов
/ 23 сентября 2019

Когда вы вызываете этот код:

act = () => Console.Write(++count + " ");

Вы захватываете локальную переменную count внутри действия.Каждый последующий вызов act() использует эту захваченную переменную.Таким образом, если он начинается с 0, он становится 1, 2, а затем 3.

Таким образом, с частью if(act == null) вы будете назначать act только один раз, поэтому второй вызов Test() не переназначает act и не фиксирует новую переменную count.Следовательно, он продолжает использовать исходный, то есть он увеличивается до 3.

Без оператора if вы захватываете новую переменную count каждый раз, когда вызываете Test(), поэтому она эффективно сбрасывается в 0.

Это связанный вопрос .

1 голос
/ 23 сентября 2019

Без проверки, если act равно null, когда вы вызываете Test () во второй раз, он назначает новую встроенную функцию для действия.

Каждый inline act () имеет доступ к разной версии счетчика впамять кучи.

Чтобы понять, подумайте, что компилятор "напоминает", что каждое действие имеет доступ к последнему вызову пространства памяти Test.

Каждый раз, когда вызывается Test, он создает отдельную кучупробел, поэтому count имеет другое значение.

Если вы проверяете, является ли act нулевым, и не создаете новую встроенную функцию act, действие использует только один счет.

Если вы создаете новый акт из-зане проверяя нулевое значение, каждое действие имеет доступ к новой версии счетчика, как если бы это был новый экземпляр объекта, имеющего счет в качестве члена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...