问题
为什么"out"参数作为一种语言结构存在于C#中?
对该问题的阐述
为什么它首先存在?难道没有更好的语言功能可以获得与"out"参数相同的效果吗?
让一个值类型表现得像引用类型,这不是很奇怪吗?
难道没有更好的方法从一个方法返回多个值吗?
这是一件历史性的事情吗?这意味着在C#的第一个版本中,没有办法实现out参数可以实现的东西,但现在有了新的功能,它只是保留在语言中以实现向后兼容性?
我没有问什么
- 我不是在问它有什么作用
- out参数修饰符(C#参考)
- 我不是在问它是如何使用的
- https://stackoverflow.com/a/8128838/33311
- ";out";关键字(在C#中)
- 我不是在问"ref"one_answers"out"有什么区别
- 什么';s;ref';和';out';关键词
- 我读到应该避免使用它,而选择其他结构
- 使用";out";C中的关键字#
我在阅读类似的问题时没有发现任何重复。
预期答案格式
我很想听到这样的话,"看,这是一个问题,你只能通过使用"out"参数语言结构来解决,这里有一个代码示例…"。
或者,"看,这曾经是解决以下问题的唯一方法…代码示例…,但由于C#版本…更好的解决方法是这样…代码示例。"。
请不要发表意见。
C#编译器执行确定赋值检查。这就要求它准确地知道变量何时被赋值。通常不难理解,一项任务很容易回头看。
但有一种情况是,当一个变量通过引用传递给另一个方法时。该方法是否要求在调用之前分配该变量,然后对其进行修改,还是只分配它?编译器通常无法知道,方法可能存在于另一个程序集中,而方法体不可用。例如,对于任何.NET Framework程序集都为True。
所以你必须明确,当方法需要在调用前分配参数时,你使用ref
,当方法只分配参数时使用out
。顺便说一句,这是一个很好的功能,它消除了一大堆非常常见的错误。
关于这个问题的其他错误答案的一条注释。数据流在pinvoke中也起着重要作用,pinvoke整理器需要知道是否转换非托管函数返回的任何数据。它不关注out-vs-ref关键字,只关注[In]
和[Out]
属性。更多关于这个问题的细节。
一个原因是与Win32 API等兼容。如果要直接从C#调用Win32 API调用的某些方法声明,则需要使用out和/或ref。
你可以在pinvoke.net上找到一些这样的方法声明的例子:http://pinvoke.net/search.aspx?search=out&namespace=[All]
为什么它首先存在?难道没有更好的语言功能可以获得与"out"参数相同的效果吗?
什么是"更好"?基于C#7的争论,事情更容易一些,是这样的吗:
public static (bool Succesful, int Value) TryParse(string s) { ... }
var parseResult = TryParse(s);
if (parResult.Succesful)
DoSomething(parResult.Result);
比?
if (int.TryParse(s, out var i))
DoSomething(i);
嗯。。。。
在原生元组支持之前,实际上必须实现一个结构/类才能返回多个值。。。。真恶心。的确,out
解决方案也不会那么干净,但它仍然是一个更好的选择,而不是为了让方法返回多个值而不得不在代码库中丢弃大量的轻量级容器类。
让一个值类型表现得像引用类型不是很奇怪吗?
为什么?即使它只是为了向后兼容或互操作,它也是必需的语言功能。
阿,你把事情搞混了。如果想要传递引用语义,可以使用ref
关键字。out
关键字表示该参数将用作返回值;它需要通过引用传递,这是一个实现细节。
难道没有更好的方法从一个方法返回多个值吗?
这基本上是你重写的第一个问题。
这是一件历史性的事情吗?这意味着在C#的第一个版本中,没有办法实现使用out参数可以实现的事情,但现在有了新的功能,它只是保留在语言中以向后兼容?
向后兼容性是显而易见的重要原因。此外,仅仅因为有更好的方法来做事情并不一定意味着语言功能应该被删除。然后,您可以为许多其他语言构造提供一个案例:for
循环、goto
等。