我不明白为什么在调用带有out
参数的方法时必须声明变量,即使我不关心方法提供的out
值
对我来说,它似乎类似于调用返回值为bool Foo()
但不消耗Foo();
的方法。将out
参数标记为可选的可能性会使我的代码更清晰,或者会让API开发人员在没有方法out
参数的情况下编写重载。
那么,out参数不可选是什么原因?
答案 0 :(得分:3)
我认为没有一个真正的理由不能。也许原因只是:因为它是记录在案的。
据我所知,没有任何编译器魔法让out
变得特别。看看这个CIL代码:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 17 (0x11)
.maxstack 1
.locals init ([0] int32 y)
IL_0000: nop
IL_0001: ldloca.s y
IL_0003: call void ConsoleApplication15.Program::X(int32&)
IL_0008: nop
IL_0009: ldloc.0
IL_000a: call void [mscorlib]System.Console::WriteLine(int32)
IL_000f: nop
IL_0010: ret
} // end of method Program::Main
.method public hidebysig static void X([out] int32& i) cil managed
{
// Code size 6 (0x6)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldc.i4.s 10
IL_0004: stind.i4
IL_0005: ret
} // end of method Program::X
源自此方法:
public static void X(out int i)
{
i = 10;
}
static void Main(string[] args)
{
int y;
X(out y);
Console.WriteLine(y);
}
如您所见,变量在调用方法中分配,值通过“引用”传递。定义out
参数'just'的默认值会中断检查是否设置了值(因为它已经存在)。
另外,作为Damien_The_Unbeliever commented,它可能只是在可选参数的初始构建中被忽略/跳过的功能,因为out
已经存在。
答案 1 :(得分:1)
Out参数是编译技巧。 CLR世界中没有任何称为out
参数的东西。它实际上是传递给方法的ref
参数。
区别在于编译器将确保在方法退出之前分配值。就是这样。
因此,当您需要使用ref / out参数调用方法时,您不需要值,而是需要对变量/字段的引用。
对于可选参数,c#编译器在调用方法时会传递默认值,但在这里你不能;你需要一个参考。
如果编译器必须支持此功能,则必须为您创建变量,通过引用传递它并忽略结果。正如你所看到的,这是一个丑陋的事情,因此我们没有这个功能。
答案 2 :(得分:0)
"当前" C#编译器(前Roslyn)非常复杂,在Microsoft,他们只在严格必要时才尝试修改它。 COM互操作所需的可选参数,因此他们添加了它们。或许可选择输出参数。
我们希望通过Roslyn,编译器可以更快地进步,我们将进入语法bloath的新时代: - )
有人在Roslyn github上对此进行了功能请求:https://github.com/dotnet/roslyn/issues/186
答案 3 :(得分:0)
我认为这个讨论有两个层次。技术水平和功能水平。
在技术层面上,问题应该是:它是否可能/可以完成?在这种情况下,答案是肯定的。对于编译器,很容易创建一个隐藏的局部,并使用可选的out参数调用该方法,并引用这个隐藏的局部。
在功能层面,我们应该问自己:这是我们真正想要的吗?
我的意见是:为什么不呢?当我们调用一个函数时,我们已经忽略了返回值而没有结果。那么为什么我们不允许(自动)忽略来自(可选)out-parameter的值?
此外,我们可能会遇到与该方法的其他重载冲突,但作为状态,我们在使用选项时已经存在这些冲突,所以没有新的。
最后,由C#的设计者决定。他们应该回答这两个问题:这是否可能,我们是否想要这个?