What is the purpose of the “out” keyword at the caller (in C#)?
当一个c函数有一个输出参数时,您可以按如下说明:
1
| private void f(out OutputParameterClass outputParameter); |
这说明调用函数时不必初始化参数。但是,调用此函数时,必须重复out关键字:
我想知道这对什么有好处。为什么需要重复部分功能规范?有人知道吗?
这意味着你知道你在做什么——你承认这是一个out参数。你真的想让完全不同的行为安静地发生吗?顺便说一下,ref也是如此。
(您也可以根据值vs out/ref进行重载,但我不推荐这样做。)
基本上,如果您有一个(未捕获的)局部变量,并将其用作非out/ref参数,那么您知道该变量的值在方法中不会被更改。(如果它是一个引用类型变量,那么它引用的对象中的数据可能会被更改,但这是非常不同的。)
这避免了C++中的那种情况,在那里你不知不觉地通过引用传递某些东西,但是假设值没有改变…
- 确切地。如果被呼叫者无意识地改变了你的变量,它会引起巨大的头痛。
- 在这里!php"通过引用返回"(或通过引用传递参数,相同的事情),通过在分配返回值时排除和号,可以忽略"通过引用"。讨论一个疯狂的虫子,当你只剩下一个和符号的时候。在C中要求"out"是避免此类错误的最明智的方法。
- 出于好奇心,为什么不建议在外面超载呢?它对性能有影响,还是对可读性有影响?
- @mehrdad:在c中,所有类实例都是通过引用传递的。
- "这避免了C++中你在不知不觉中传递某些东西的情况":在C++中,大多数函数参数应该标记为"const"。在这种情况下,您(几乎)肯定不会修改您的变量。
- @迪米特里:不,不是。引用是按值传递的。有很大的不同。请阅读pobox.com/~skeet/csharp/parameters.html
- @迪米特里:你只知道警察的情况,如果你检查签名,在这种情况下,你已经知道它是由参考。
- 迪米特里C:引用乔恩的话:"根本不会传递对象。引用是按值传递的。"
- @皮埃尔·阿兰:超载会让人很困惑。通过这样一个相对微妙的事情(比如如何传递参数)进行重载几乎会导致混淆。
- 如果"out"关键字需要复制,那么您是否还要复制参数类型呢?
- @dimitri:编译器已经通过静态类型强制执行了这些操作-参数类型必须隐式转换为参数类型,或者在引用/输出的情况下,它们必须完全相同。
- 重复out/ref的最重要原因是,如果用不同的签名重构您所调用的函数,您将得到一个编译错误。最值得注意的是,如果一个参数从非out变为out,您马上就会知道。
- @jon,@dimitri c.:另外,调用代码的读者可能不知道函数签名中的out/ref。另一方面,通过了解实际参数的类型,可以很容易地推断出参数类型。
- @这是一句很好的话。我没想到!把它作为答案贴出来不是更好吗?
- 在我看来,如果这种重复只是为了清晰起见,那么它只会增加口头表达。然而,我认为普林特的话是有意义的,因为它有助于重构。
- @迪米特里C。我认为它确实提高了清晰度。
- @迪米特里:记住,这种重复(通常)不是在同一个文件中的两位代码之间进行的。它介于一个方法参数(您甚至可能没有其源)和您碰巧看到的方法参数之间。就我个人而言,我希望能够在不必查找每个签名以检查它是否有任何引用/输出参数的情况下,大致了解代码将做什么。
这是一个设计特点。很明显,这是不必要的,但它有助于可读性。
对于可读性,了解方法可以/将对变量做什么。
从msdn获得更多信息:http://msdn.microsoft.com/en-us/vcsharp/aa336814.aspx
The caller of a method which takes an
out parameter is not required to
assign to the variable passed as the
out parameter prior to the call;
however, the callee is required to
assign to the out parameter before
returning.
虽然我不知道这种决定的起源,但我知道它有超载的目的。
在同一类中创建这两个函数是完全合法的:
1
| private void f(out OutputParameterClass outputParameter); |
和
1
| private void f(OutputParameterClass outputParameter); |
调用此类重载时指定out关键字是有意义的。
我认为这是一个一致性和清晰性的问题。
很明显,没有这个编译器就可以做得很好。但是,添加了out关键字后,您的意图就变得清晰了,代码也变得清晰易读。
我能看到的唯一原因是确保函数的用户知道函数可以修改这个参数的值。我觉得这是件好事。
- 它不仅可以被修改,而且会被修改。
- 丹尼尔:不是真的。它可以使函数保持不变。out由编译器强制执行。如果声明函数是用另一种语言编写的,它可能会选择不强制执行明确的赋值。
- 用另一种语言?哪一个?
- 例如,您在IL中构建自己的函数,并用out属性对其进行修饰。然后您将有一个C方法调用它。
- 在任何情况下,C(这是问题的标记)中的out参数必须在函数中赋值给它。当然,您可以尝试跳过它,但我认为在不尊重修饰符语义的情况下使用这种修饰符(out,ref)没有多大意义。
我得到的最佳答案是普林特发表的评论:
重复out/ref的最重要原因是,如果用不同的签名重构您所调用的函数,您将得到一个编译错误。最值得注意的是,如果一个参数从非out变为out,您马上就会知道。
为了清晰起见,您可能需要使用out。如果不看方法签名就不知道。
- 由于out和ref之间的明确分配差异,您得到的示例不起作用。