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不,“知道”的人说