我有一些代码,
int count = 0;
list.ForEach(i => i.SomeFunction(count++));
这似乎不会增加计数。计数是否按此值传递?如果我在lambda中使用{}会有什么不同吗?
int count = 0;
list.ForEach(i =>
{
i.SomeFunction(count++);
});
更新1
抱歉,我的错误,确实更新了原始计数。
答案 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
。