在lambdaexpression式中不能使用ref或out参数

为什么不能在lambdaexpression式中使用ref或out参数?

我今天遇到了错误,发现一个解决方法,但我仍然好奇,为什么这是一个编译时错误。

这是一个简单的例子:

private void Foo() { int value; Bar(out value); } private void Bar(out int value) { value = 3; int[] array = { 1, 2, 3, 4, 5 }; int newValue = array.Where(a => a == value).First(); } 

兰巴达斯具有改变他们捕获的variables的生命周期的外观。 例如,下面的lambdaexpression式导致参数p1比当前的方法帧活得更长,因为在方法帧不再在堆栈上之后可以访问它的值

 Func<int> Example(int p1) { return () => p1; } 

捕获的variables的另一个属性是对variables的更改在lambdaexpression式之外也是可见的。 例如下面的打印42

 void Example2(int p1) { Action del = () => { p1 = 42; } del(); Console.WriteLine(p1); } 

这两个属性产生一定的效果,这些效果以下面的方式在ref参数中飞行

  • 参数参数可能有一个固定的寿命。 考虑将一个局部variables作为refparameter passing给一个函数。
  • lambda中的副作用需要在ref参数本身上可见。 在方法和调用者中。

这些是有些不兼容的属性,是在lambdaexpression式中不允许的原因之一。

在引擎盖下,匿名方法是通过提取捕获的variables (这是你的问题主体的全部内容)并将它们存储为编译器生成的类的字段来实现的。 无法将refout参数存储为字段。 Eric Lippert在一篇博客文章中对此进行了讨论。 请注意,捕获的variables和lambda参数是有区别的。 由于它们不是捕获variables,因此可以具有如下所示的“forms参数”:

 delegate void TestDelegate (out int x); static void Main(string[] args) { TestDelegate testDel = (out int x) => { x = 10; }; int p; testDel(out p); Console.WriteLine(p); } 

你可以,但是你必须明确地定义所有的types

 (a, b, c, ref d) => {...} 

无效,但是

 (int a, int b, int c, ref int d) => {...} 

已validation

由于这是Google上“C#lambda ref”的最佳结果之一, 我觉得我需要扩展上述的答案。 旧的(C#2.0)匿名委托语法的作品,它支持更复杂的签名(以及闭包)。 Lambda和匿名代表至less在编译器后端共享感知实现(如果它们不相同) – 最重要的是,它们支持闭包。

当我进行search时,我正在尝试做什么来演示语法:

 public static ScanOperation<TToken> CreateScanOperation( PrattTokenDefinition<TNode, TToken, TParser, TSelf> tokenDefinition) { var oldScanOperation = tokenDefinition.ScanOperation; // Closures still work. return delegate(string text, ref int position, ref PositionInformation currentPosition) { var token = oldScanOperation(text, ref position, ref currentPosition); if (token == null) return null; if (tokenDefinition.LeftDenotation != null) token._led = tokenDefinition.LeftDenotation(token); if (tokenDefinition.NullDenotation != null) token._nud = tokenDefinition.NullDenotation(token); token.Identifier = tokenDefinition.Identifier; token.LeftBindingPower = tokenDefinition.LeftBindingPower; token.OnInitialize(); return token; }; } 

请记住,Lambdas在程序上和math上更安全(因为前面提到的ref ref值的提升):你可能会打开一堆蠕虫。 使用这种语法时请仔细考虑。