Does C# Pass by Value to Lambdas?

2019-06-22 05:46发布

I have some code,

int count = 0;

list.ForEach(i => i.SomeFunction(count++));

This seems to not increment count. Is count passed by value here? Is there any difference if I use the {} in the lambda?

int count = 0;

list.ForEach(i => 
            {
                    i.SomeFunction(count++);
            });

Update 1

Sorry, my mistake, it does update the original count.

9条回答
啃猪蹄的小仙女
2楼-- · 2019-06-22 06:06

In this case, the count variable is captured. Even if it's a struct the captured variable acts like its a reference. So, you would certainly see an incremented count after the foreach.

查看更多
smile是对你的礼貌
3楼-- · 2019-06-22 06:12

In both cases you are creating what's called a closure. Essentially, count is being wrapped in a class and that class is being used by the lambda expression.

Bill Wagner has a great book called More Effective C# and he has a blog post that describes closures in more detail.

查看更多
乱世女痞
4楼-- · 2019-06-22 06:15

That should increment, proof:

class Foo
{
    public void SomeFunction(int i) { }
}
static void Main()
{
    int count = 0;
    List<Foo> list = new List<Foo> {new Foo()};
    list.ForEach(i => i.SomeFunction(count++));
    Console.WriteLine(count); // 1
}

The lambda acts (as already stated) to "capture" count, essentially making the code like:

class Foo
{
    public void SomeFunction(int i) { }
}
class CaptureScope
{
    public int count;
    public void AnonMethod(Foo foo)
    {
        foo.SomeFunction(count++);
    }
}
static void Main()
{
    CaptureScope scope = new CaptureScope();
    scope.count = 0;
    List<Foo> list = new List<Foo> {new Foo()};
    list.ForEach(scope.AnonMethod);
    Console.WriteLine(scope.count); // 1
}

The above is a rough approximation of how the compiler interprets a delegate lambda. As you can see, the count is a field on a class, and is incremented.

查看更多
做个烂人
5楼-- · 2019-06-22 06:15

Lambdas are anonymous functions, and as such, follow the same rules as passing arguments into a function.

查看更多
霸刀☆藐视天下
6楼-- · 2019-06-22 06:16

count is an int, and ints are value types, which means they are indeed passed by value. There is no semantic difference between your first and second example.

(That said, it looks to me like it should be incrementing count, since it should be capturing the original reference as far as the closure. To clarify -- although count will be passed by value down into SomeFunction, things don't get "passed" into your lambda expression when you use them inside the expression -- they are the same reference as the external variable.)

查看更多
该账号已被封号
7楼-- · 2019-06-22 06:21

That should capture (close over) count as a closure.

查看更多
登录 后发表回答