不能在lambda表达式中使用ref或out参数

ska*_*alb 161 c# lambda

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

我今天遇到了错误并找到了解决方法,但我仍然很好奇为什么这是编译时错误.

CS1628:不能在匿名方法,lambda表达式或查询表达式中的ref或out参数'parameter'中使用

这是一个简单的例子:

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();
}
Run Code Online (Sandbox Code Playgroud)

Jar*_*Par 117

Lambda具有改变它们捕获的变量的生命周期的外观.例如以下lambda表达式引起的参数P1到长于当前方法帧作为它的值可以在方法帧之后访问是不再在堆栈上

Func<int> Example(int p1) {
  return () => p1;
}
Run Code Online (Sandbox Code Playgroud)

捕获变量的另一个属性是变量的变化在lambda表达式之外也是可见的.例如,以下打印42

void Example2(int p1) {
  Action del = () => { p1 = 42; }
  del();
  Console.WriteLine(p1);
}
Run Code Online (Sandbox Code Playgroud)

这两个属性产生一组特定的效果,它们以下列方式面对ref参数

  • ref参数可能具有固定的生命周期.考虑将局部变量作为ref参数传递给函数.
  • lambda中的副作用需要在ref参数本身上可见.在方法和调用者中.

这些是一些不兼容的属性,也是lambda表达式中不允许它们的原因之一.

  • 我知道我们不能在lambda表达式中使用`ref`,但是没有使用它的欲望. (31认同)
  • 如果你仍然想使用它,那么你可以创建一个临时变量并在 lamda 中使用它。类似于`int tempVariable = refVariable; int newValue = array.Where(a =&gt; a == tempVariable).First();` (4认同)

Meh*_*ari 81

在引擎盖下,匿名方法是通过提升捕获的变量(这是你的问题主体所有)来实现的,并将它们存储为编译器生成的类的字段.无法将参数refout参数存储为字段.Eric Lippert在博客文章中对此进行讨论.请注意,捕获的变量和lambda参数之间存在差异.您可以拥有如下所示的"形式参数",因为它们不是捕获的变量:

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);
}
Run Code Online (Sandbox Code Playgroud)


Ben*_*ams 63

您可以但必须明确定义所有类型

(a, b, c, ref d) => {...}
Run Code Online (Sandbox Code Playgroud)

但是,无效

(int a, int b, int c, ref int d) => {...}
Run Code Online (Sandbox Code Playgroud)

已验证

  • 它没有; 问题是为什么你不能在lambda中引用已经定义的`ref`或`out`的*现有变量*.很明显,如果您阅读示例代码(再次尝试再次阅读).接受的答案清楚地解释了原因.你的答案是关于对lambda使用`ref`或`out`*参数*.完全没有回答问题并谈论别的事情 (22认同)
  • 它确实; 问题是为什么你不能; 答案就是你可以. (13认同)
  • @ edc65是对的...这与问题的主题无关,这与lamba表达式的内容(右侧)有关,而与其参数列表(左侧)无关.奇怪的是,这得到了26个赞成票. (4认同)
  • 它确实帮助了我.为此+1.谢谢 (4认同)

Jon*_*son 5

因为这是Google上"C#lambda ref"的最佳结果之一; 我觉得我需要扩展上面的答案.旧的(C#2.0)匿名委托语法有效,它确实支持更复杂的签名(以及闭包).Lambda和匿名委托至少在编译器后端共享感知实现(如果它们不相同) - 最重要的是,它们支持闭包.

我在搜索时尝试做的事情,以演示语法:

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;
        };
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我想你误解了这个问题.问题是为什么lambda无法在其容器方法中访问ref/out变量,而不是为什么_lambda本身_不能包含ref/out变量.AFAIK后者没有充分的理由.今天我写了一个lambda`(a,b,c,ref d)=> {...}`和`ref`是红色下划线的,错误信息"参数'4'必须用'ref'关键字声明".捂脸!PS什么是"参考价值促销"? (3认同)