首页 文章

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

提问于
浏览
141

为什么不能在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();
}

4 回答

  • 5

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

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

    但是,无效

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

    已验证

  • 52

    Lambda具有改变它们捕获的变量的生命周期的外观 . 例如,以下lambda表达式导致参数p1比当前方法帧更长寿,因为在方法帧不再位于堆栈之后可以访问其值

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

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

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

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

    • ref参数可能具有固定的生命周期 . 考虑将局部变量作为ref参数传递给函数 .

    • lambda中的副作用需要在ref参数本身上可见 . 在方法和调用者中 .

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

  • 75

    在引擎盖下,匿名方法是通过提升 captured variables (这是你的问题主体所有)来实现的,并将它们存储为编译器生成的类的字段 . 无法将 refout 参数存储为字段 . Eric Lippert在a blog entry讨论过它 . 请注意,捕获的变量和lambda参数之间存在差异 . 你 can 喜欢以下内容,因为它们不是捕获的变量:

    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);
    }
    
  • 102

    因为这是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;
            };
    }
    

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

相关问题