简体   繁体   English

C# lambda 使用局部变量

[英]C# lambda use local variable

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 + " ");
        }
    }  

result : 1 2 3 why?结果1 2 3为什么?

if delete [ if(act == null) ] result : 1 2 1如果delete [ if(act == null) ]结果1 2 1

Currently, you're only creating a single delegate instance.目前,您只创建一个委托实例。 That captures the local variable that was declared in the Test method the first time it was called.这将捕获第一次调用Test方法时声明的局部变量。

That local variable effectively has an extended lifetime due to the delegate that captures it.由于捕获它的委托,该局部变量有效地延长了生命周期。 Every time you invoke the delegate, it increments the same variable.每次调用委托时,它都会增加相同的变量。

When you remove the if (act == null) condition, you create a new delegate each time you call Test , which means it captures a different count local variable, starting at 0 each time.当您删除if (act == null)条件时,每次调用Test时都会创建一个新委托,这意味着它会捕获不同的count局部变量,每次都从 0 开始。 You're calling Test() twice, and the delegate created through the first call is invoked twice (with output 1 then 2).您调用Test()两次,通过第一次调用创建的委托被调用两次(output 1 然后 2)。 The delegate create through the second call is only invoked once (with output 1).通过第二次调用创建的委托仅被调用一次(使用 output 1)。

When you call this code:当您调用此代码时:

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

You capture the local variable count within the action.您在操作中捕获局部变量count Each subsequent call to act() uses this captured variable.act()的每个后续调用都使用此捕获的变量。 So if it starts as 0, it becomes 1, 2, and then 3.所以如果它从 0 开始,它会变成 1、2,然后是 3。

So with the if(act == null) part, you will only ever assign act a single time, so the second call to Test() doesn't reassign act and doesn't capture the new count variable.因此,使用if(act == null)部分,您只会分配一次act ,因此对Test()的第二次调用不会重新分配act并且不会捕获新的count变量。 Therefore, it keeps using the original one, meaning it increments to 3.因此,它继续使用原始的,这意味着它增加到 3。

Without the if statement, you capture the new count variable each time you call Test() , so it effectively resets to 0.如果没有if语句,每次调用Test()时都会捕获新的count变量,因此它实际上会重置为 0。

This is a related question . 这是一个相关的问题

Without testing if act is null, when you call Test() for the second time, it assigns a new inline function to act.如果不测试 act 是否为 null,当您第二次调用 Test() 时,它会分配一个新的内联 function 来执行。

Each inline act() have access to a different count version in the heap memory.每个内联 act() 都可以访问堆 memory 中的不同计数版本。

To understand, think that the compiler "reminds" that each act has access to the last call to Test memory space.要理解,认为编译器“提醒”每个动作都可以访问最后一次调用 Test memory 空间。

Each time Test is called, it creates a distinct heap space, so count has different value.每次调用 Test 时,都会创建一个不同的堆空间,因此 count 具有不同的值。

If you test if act is null and not create a new act inline function, act use only one count.如果您测试 act 是否为 null 并且没有创建新的内联动作 function,则仅使用一个计数。

If you create a new act because of not testing if null, each act has access to a new count version like if it was a new instance of an object having count as member.如果您因为未测试 null 而创建新行为,则每个行为都可以访问新的计数版本,就像它是 object 的新实例一样,它被视为成员。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM