代码之家  ›  专栏  ›  技术社区  ›  Chris Ballance

为什么匿名方法中不允许out参数?

  •  14
  • Chris Ballance  · 技术社区  · 15 年前

    这不是一个骗局 Calling a method with ref or out parameters from an anonymous method

    我想知道 为什么? 匿名方法中不允许使用out参数。不允许 裁判 参数对我来说更有意义,但是 外面的 参数,不多。

    你对这个有什么看法

    4 回复  |  直到 10 年前
        1
  •  29
  •   George Stocker NotMe    15 年前

    在某些方面,这是一个骗局。 Out 参数是 ref 参数。C语言使用的值有一个额外的属性。不允许它们的原因与 裁判 参数。

    这里的问题源于使用匿名方法内部的匿名方法之外声明的值的效果。这样做将捕获lambda中的值,并且出于必要,可以任意地将其寿命延长到当前函数的寿命之外。这与不兼容 out 具有固定寿命的参数。

    例如,假设 外面的 参数引用了堆栈上的局部变量。lambda可以在将来的任意点执行,因此可以在堆栈帧不再有效时执行。会有什么 外面的 参数平均值?

        2
  •  6
  •   Chris Ballance    10 年前

    这基本上是因为匿名委托/lambda表达式的参数是 捕获的变量 捕捉 ref / out 变量在C/clr中没有任何意义,因为它需要 裁判 / 外面的 领域 内部的。另外,请注意,我将这两个关键字配对,因为它们实际上是相同的。

    如果你想要一个完整的解释, Eric Lippert discussed this design point in detail 在他的博客上。(特别参见底部附近的段落。)

        3
  •  1
  •   SLaks    15 年前

    唯一的区别是 out ref 参数是一个 外面的 参数将具有 [out] 应用到它的令牌。就CLR而言,它们是相同的。

    为了实现它,编译器必须生成 裁判 领域 ,不支持。

    如果你仔细想想,你会发现允许匿名方法使用 外面的 参数。

    以下代码将用于什么?

    static Func<object, object> Mess(out object param) {
        param = "Original";
        return i => param = i;
    }
    static Func<object, object> MessCaller() {
        object local;
        return Mess(out local);
    }
    static vouid Main() {
        Console.WriteLine(MessCaller()("New"));
        //The local variable that the lambda expression writes to doesn't exist anymore.
    }
    
        4
  •  1
  •   Simon Miller    12 年前

    我在开发一些错误处理代码时遇到了这个难题。我想把一个引用传递给一个将被记录的错误消息。这使我的匿名方法有机会执行多个检查,每个检查都会根据需要设置错误消息。

    最后我为匿名方法编写了一个新的包装器,它的工作方式不同。但是我认为对某些人来说可能是有价值的,我可以简单地创建一个带有out参数的私有方法,并定义一个委托,然后让我的代码使用它。希望这能帮助/激励某人。

        protected delegate void OutStringDelegate(int divider, out string errorText);
        protected void codeWrapper(int divider, OutStringDelegate del)
        {
            string ErrorMessage = "An Error Occurred.";
    
            try
            {
                del(divider, out ErrorMessage);
            }
            catch
            {
                LogError(ErrorMessage);
            }
        }
        public void UseWrapper(int input)
        {
            codeWrapper(input, codeToCall);
        }
        private int somePrivateValue = 0;
        private void codeToCall(int divider, out string errorMessage)
        {
            errorMessage = "Nice Error Message here!";
            somePrivateValue = 1 / divider; // call me with zero to cause error.
        }
        private void LogError(string msg)
        {
            Console.WriteLine(msg);
        }
    
    推荐文章