C# out参数不能为可选参数的原因是什么?
我不明白为什么调用带有C# out参数不能为可选参数的原因是什么?,c#,C#,我不明白为什么调用带有out参数的方法时必须声明变量,即使我不关心该方法提供的out值 在我看来,这类似于调用一个返回值为boolfoo()的方法,但不使用它Foo()。如果能够将out参数标记为可选参数,则会使我的代码更干净,或者避免API开发人员在没有方法的out参数的情况下编写重载 那么,out参数不能作为可选参数的原因是什么呢?当前的C#编译器(pre-Roslyn)非常复杂,在Microsoft,他们只在严格必要时才尝试修改它。COM互操作所需的可选参数,因此他们添加了这些参数。也许可
out
参数的方法时必须声明变量,即使我不关心该方法提供的out
值
在我看来,这类似于调用一个返回值为boolfoo()
的方法,但不使用它Foo()代码>。如果能够将out
参数标记为可选参数,则会使我的代码更干净,或者避免API开发人员在没有方法的out
参数的情况下编写重载
那么,out参数不能作为可选参数的原因是什么呢?当前的C#编译器(pre-Roslyn)非常复杂,在Microsoft,他们只在严格必要时才尝试修改它。COM互操作所需的可选参数,因此他们添加了这些参数。也许可选的输出参数不是必需的
我们希望,有了Roslyn,编译器将发展得更快,我们将进入一个新的语法时代:bloath:-)
有人在Roslyn github上为此做了一个功能请求:输出参数是编译器技巧。在CLR世界中没有所谓的out
参数。它实际上是传递给方法的ref
参数
不同之处在于编译器将确保在方法退出之前赋值。就这样
因此,当您需要使用ref/out参数调用方法时,您不需要值,而是需要对变量/字段的引用
对于可选参数,c#编译器将在调用方法时传递默认值,但在这里不能;你需要一个推荐人
如果编译器必须支持此功能,它必须为您创建一个变量,通过引用传递它并忽略结果。正如你所看到的,这是一件很难看的事情,因此我们没有这个功能。我认为没有真正的理由说明它不能。也许原因只是:因为它是有文件记录的
据我所知,没有任何编译器魔法使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”定义默认值会中断检查是否设置了值(因为已经设置了)
同样,在可选参数的初始构建中,它可能只是一个被忽略/跳过的特性,因为out
在那时就已经存在了。我认为这个讨论有两个层次。技术层面和功能层面
在技术层面上,问题应该是:是否可能/能够做到?在这种情况下,答案是肯定的。对于编译器来说,创建一个隐藏的局部函数并使用可选的out参数调用该方法非常容易,out参数引用了这个隐藏的局部函数
在功能层面上,我们应该问自己:这是我们真正想要的吗
我的意见是:为什么不呢?当我们调用一个函数时,我们已经忽略了返回值,结果是nothing。那么,为什么不允许我们(自动)忽略(可选)out参数中的值呢
此外,我们可能会与该方法的其他重载发生冲突,但作为state,我们在使用optionals时已经存在这些冲突,因此没有什么新的内容
归根结底,这取决于C#的设计者。他们应该回答这两个问题:这可能吗?我们想要这个吗?你有没有一个例子说明这是可选的?在我所能想到的所有时间里,out参数都是用来提供有用信息的information@Sayse您可以使用int.TryParse
检查字符串是否为数字,同时对其值不感兴趣。有些用例可以忽略out参数。@SonerGönül没有解释原因。@xanatos-是的,但同时如果它是一个数字,您很有可能希望在以后的某个地方使用该数字。请记住,out
自C#1.0以来就已经存在。“可选”是在很久以后(对C#)引入的。在这次讨论中,我认为对否决票的解释将非常有用,所以否决票的选民,请这样做。@Patrickhoffman Stackoverflow我想已经变成了meta。如果人们不喜欢你的答案,他们往往会投反对票:\n嗯,我发现最后一句话非常有趣(如果它是一个对象,没有默认构造函数会怎么样…)。我想你可能是对的+1@Patrick霍曼:是和否。使用
的中的值被分配给隐藏的本地。当失去作用域时,将处理隐藏的局部,而不是给定的局部。您可以尝试在使用范围内更改给定的本地文件,并查看它是否会被释放。您将看到原始对象将被处置,而不是新分配的值。因此。。。我们创造隐藏的本地人。。。没关系。我们已经忽略了返回值。。。那也没关系。那么,当我们将这两者结合起来时,为什么会变得“丑陋”呢?使用这种推理,即使是可选参数也是编译器的一种技巧,它们在CIL级别上并不存在。out
和“可选”都是编译器技巧,仅受meta语言的支持attributes@xanatos:有参考资料吗?另外,[opt]
是CIL参数属性。反汇编。5设置为呼叫端(IL_0001:ldc.i4.5)是。。。也许我误解了你的答案。。。现在我重读了它,没有什么我不同意的(或者说得更清楚一点:我同意你所有的回答)。编译器很难为变量提供默认分配(对于引用类型,唯一的逻辑内容是null),但这是错误的<代码>默认值(T)
在C中始终有效#在本次讨论中,我认为对否决票的解释将非常有用,所以否决票,请这样做。我认为编译器的复杂性不是一个参数。编译器解决了比这更大的问题。@MartinMulder不,“知道”的人说