这不是Calling a method with ref or out parameters from an anonymous method
的欺骗我想知道匿名方法中不允许使用为什么 out参数。不允许 ref 参数对我来说更有意义,但 out 参数不是那么多。
您对此有何看法
答案 0 :(得分:29)
在某些方面,这是一个骗局。 Out
个参数是ref
个参数。 C#语言使用的值只有一个额外的属性。禁止它们的原因与ref
参数完全相同。
这里的问题源于在匿名方法中使用匿名方法之外声明的值的效果。这样做会捕获lambda中的值,并且必然会将其生命周期延长到超出当前函数的寿命。这与具有固定生命周期的out
参数不兼容。
想象一下,例如out
参数引用堆栈上的局部变量。 lambda可以在将来的任意点执行,因此可以在该堆栈帧不再有效时执行。那么out
参数意味着什么?
答案 1 :(得分:6)
这基本上与匿名委托/ lambda表达式的参数是捕获变量这一事实有关,并且捕获ref
/ out
变量不会产生任何变量在C#/ CLR中有意义,因为它内部需要ref
/ out
字段。另外,请注意我将这两个关键字配对,因为它们实际上是相同的。
如果您想在他的博客上提供完整的解释Eric Lippert discussed this design point in detail。 (特别参见底部附近的段落。)
答案 2 :(得分:1)
out
和ref
参数之间的唯一区别是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.
}
答案 3 :(得分:1)
我在开发一些错误处理代码时遇到了这个难题。我想将引用(out)传递给将被记录的错误消息。这使我的匿名方法有机会执行多次检查,每次检查都根据需要设置错误消息。
我最终为匿名方法编写了一个新的包装器,它的工作方式不同。但我认为对某人有一些价值的是,我可以简单地创建一个具有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);
}