15

这不是从匿名方法调用带有 ref 或 out 参数的方法的骗局

我想知道为什么匿名方法中不允许使用 out 参数。不允许ref参数对我来说更有意义,但out参数没有那么多。

你对此有何看法

4

4 回答 4

31

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

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

例如,假设out参数引用堆栈上的局部变量。lambda 可以在将来的任意点执行,因此可以在该堆栈帧不再有效时执行。那么这个out参数是什么意思呢?

于 2009-10-28T15:06:50.450 回答
6

这基本上与匿名委托/lambda 表达式的参数是捕获变量这一事实有关,并且捕获ref/out变量在 C#/CLR 中没有任何意义,因为它在内部需要ref/out 字段。另外,请注意,我将这两个关键字配对,因为它们实际上是相同的。

如果你想要一个完整的解释,Eric Lippert在他的博客上详细讨论了这个设计点。(具体见底部附近的段落。)

于 2009-10-28T15:07:09.903 回答
1

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

我最终为匿名方法编写了一个新的包装器,它的工作方式不同。但我认为可能对某人有价值的是,我可以简单地创建一个具有 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);
    }
于 2012-01-16T16:04:36.100 回答
1

outref参数之间的唯一区别是out参数将[out]应用一个标记。就 CLR 而言,它们是相同的。

为了实现它,编译器必须生成不支持的ref 字段。

如果你仔细想想,你会意识到允许匿名方法使用out参数是没有意义的。

下面的代码会做什么?

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.
}
于 2009-10-28T15:12:36.913 回答