C#是否通过Value传递给Lambdas?
我有一些代码,
int count = 0; list.ForEach(i => i.SomeFunction(count++));
这似乎没有增加计数。 计数是否按此值传递? 如果我在lambda中使用{}有什么区别吗?
int count = 0; list.ForEach(i => { i.SomeFunction(count++); });
更新1
对不起,我的错误,它确实更新了原始计数。
count
是一个int,int是值类型,这意味着它们确实是按值传递的。 您的第一个和第二个示例之间没有语义差异。
(也就是说,在我看来它应该是递增count
,因为它应该捕获原始引用直到闭包。澄清 – 虽然计数将通过值传递到SomeFunction,但事情不会得到“当你在表达式中使用它们时,将它们传递给你的lambda表达式 – 它们与外部变量的引用相同。)
在这两种情况下,您都在创建所谓的闭包。 从本质上讲,count被包装在一个类中,而该类正由lambda表达式使用。
Bill Wagner有一本名为More Effective C#的好书,他有一篇博文,更详细地介绍了闭包 。
变量计数由您的情境中的lambda表达式捕获。 调用者可以看到对count
任何更改。 所以,例如:
int count = 0; list.ForEach(i => i.SomeFunction(count++)); Console.WriteLine(count);
将显示列表的大小,因为在每次迭代时,您都会递增count
。
但是,对SomeFunction
的调用会将count++
的计算值(增量前的count
值)传递给SomeFunction
。 换句话说, SomeFunction
不能改变count
的值。
有关闭包和变量捕获的更多信息,请参阅我的闭包文章 。
这应该增加,certificate:
class Foo { public void SomeFunction(int i) { } } static void Main() { int count = 0; List list = new List {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 list = new List {new Foo()}; list.ForEach(scope.AnonMethod); Console.WriteLine(scope.count); // 1 }
以上是编译器如何解释委托lambda的粗略近似。 如您所见, count
是类中的一个字段,并且会递增。
我想在这里添加一个小修正。 变量count既不是通过值传递,也不是通过引用lambda表达式传递,因为它不是参数。 相反,该值由闭包中的lambda 捕获 。
你应该查看Raymond的主题系列 – http://blogs.msdn.com/oldnewthing/archive/2006/08/02/686456.aspx
这应该捕获(关闭)计数作为一个闭包 。
不,没有区别。 参数通常是按值进行的,除非您在用于lambda的委托定义中明确地将其设为“ref”或“out”。
Lambdas是匿名函数,因此遵循与将参数传递给函数相同的规则。
在这种情况下, 捕获 count
变量。 即使它是一个struct
,捕获的变量就像它的引用一样 。 所以,你肯定会在foreach
之后看到增加的count
。