C#是否通过价值传递给Lambdas?

时间:2009-05-12 13:21:08

标签: c# .net delegates lambda

我有一些代码,

int count = 0;

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

这似乎不会增加计数。计数是否按此值传递?如果我在lambda中使用{}会有什么不同吗?

int count = 0;

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

更新1

抱歉,我的错误,确实更新了原始计数。

9 个答案:

答案 0 :(得分:7)

count是一个int,而int是值类型,这意味着它们确实是按值传递的。您的第一个和第二个示例之间没有语义差异。

(那就是说,它看起来应该是递增count,因为它应该捕获原始引用直到闭包。澄清 - 尽管count将通过值传递到SomeFunction当你在表达式中使用它们时,事物不会被“传递”到你的lambda表达式中 - 它们与外部变量的引用相同。)

答案 1 :(得分:6)

在这两种情况下,您都在创建所谓的闭包。从本质上讲,count被包装在一个类中,而lambda表达式正在使用该类。

Bill Wagner有一本名为More Effective C#的好书,他有一篇博文,更详细地介绍了closures

答案 2 :(得分:6)

变量计数由您的情境中的lambda表达式捕获。调用者可以看到count的任何更改。所以,例如:

int count = 0;
list.ForEach(i => i.SomeFunction(count++));
Console.WriteLine(count);

将显示列表的大小,因为在每次迭代时,您都会递增count

但是,对SomeFunction的调用会将count++的评估值(增量前count的值)按值传递给{{} 1}}。换句话说,SomeFunction无法更改SomeFunction的值。

有关闭包和变量捕获的更多信息,请参阅我的closures article

答案 3 :(得分:4)

那应该增加,证明:

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
}

lambda行为(如前所述)“捕获”计数,基本上使代码如下:

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
}

以上是编译器如何解释委托lambda的粗略近似。如您所见,count是类中的字段, 递增。

答案 4 :(得分:3)

我想在这里添加一个小修正。变量count既不通过值传递,也不通过引用lambda表达式传递,因为它不是参数。而值是由闭包中的lambda 捕获

你应该查看雷蒙德关于这个主题的系列节目 - http://blogs.msdn.com/oldnewthing/archive/2006/08/02/686456.aspx

答案 5 :(得分:1)

那应该捕获(关闭)计数为closure

答案 6 :(得分:0)

不,没有区别。参数通常是按值进行的,除非您在用于lambda的委托定义中明确地将其设为“ref”或“out”。

答案 7 :(得分:0)

Lambdas是匿名函数,因此遵循与将参数传递给函数相同的规则。

答案 8 :(得分:0)

在这种情况下,count变量已捕获。即使它是struct,捕获的变量就像它的引用一样。因此,您肯定会在count之后看到递增的foreach