为什么C#中存在“ out”参数作为语言构造?

时间:2018-09-13 09:42:05

标签: c# out

问题

为什么C#中存在“ out”参数作为语言构造?

对问题的阐述

为什么它首先存在?没有更好的语言功能来获得与“ out”参数相同的效果吗?

使值类型表现得像引用类型不是很奇怪吗?

没有更好的方法可以从一个方法返回多个值?

这是否是历史性的事情,意味着在C#的第一个版本中,没有方法可以实现使用out参数可以实现的功能,但是现在有了更新的功能,并且为了保持向后兼容性,它只保留在语言中?

>

我不问的问题

  1. 我不是问它做什么
  2. 我不问如何使用
  3. 我不是问“ ref”和“ out”之间的区别是什么
  4. 我读到应该避免使用它,而选择其他结构

在阅读类似问题时我没有发现任何重复。

预期的答案格式

我很想听到类似的信息,“看,这是一个问题,您只能使用“ out”参数语言构造来解决,这是它的代码示例...“。

或者,“看,这曾经是解决以下问题的唯一方法……代码示例……,但是由于C#版本……更好的解决方法是这样的……代码示例。 ..”。

没有意见。

3 个答案:

答案 0 :(得分:12)

C#编译器执行definite assignment checking。这要求它确切地知道何时分配变量。通常不难发现,很容易回想一次作业。

但是有一个极端的情况是变量通过引用传递给另一个方法。该方法是否要求在调用之前先分配该变量,然后对其进行修改,还是只打算对其进行分配?编译器通常不知道,该方法可能存在于其他程序集中,而方法主体不可用。例如,适用于任何.NET Framework程序集。

因此,您必须明确地说,如果方法要求在调用之前分配参数,则使用ref,而仅在方法分配参数时使用out。顺便说一句,它消除了许多常见错误。


关于此问题其他错误答案的注释。数据流在pinvoke中也起着重要作用,pinvoke编组器需要知道是否转换由非托管函数返回的任何数据。它不会注意out vs ref关键字,而只注意[In][Out]属性。在this Q+A中有更多关于该细节的信息。

答案 1 :(得分:5)

一个原因是与例如Win32 API。如果要直接从C#调用Win32 API,则某些方法声明需要使用out和/或ref。

您可以在pinvoke.net上找到此类方法声明的一些示例: http://pinvoke.net/search.aspx?search=out&namespace=[All]

答案 2 :(得分:1)

  

为什么它首先存在?没有更好的语言功能来获得与“ 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);

嗯....

在原生元组支持之前,您实际上必须实现一个struct / class才能返回多个值。没错,out解决方案也不是很干净,但与必须使用大量轻量级容器类填充代码库以使方法简单地返回多个值相比,这仍然是一个更好的选择。

  

使值类型表现得像引用类型不是很奇怪吗?

为什么?即使只是为了向后兼容或互操作,它也是必需的语言功能。

阿斯洛,你在这里把事情搞混了。如果要通过引用语义传递,则可以使用ref关键字。关键字out意味着该参数将用作返回值;需要通过引用传递的事实是实现细节。

  

没有更好的方法可以从一个方法返回多个值?

这基本上是您重写的第一个问题。

  

这是否是历史性的事情,意味着在C#的第一个版本中,没有方法可以实现使用out参数可以实现的功能,但是现在有了更新的功能,并且为了保持向后兼容性,它只保留在语言中?

>

向后兼容是显而易见的重要原因。同样,仅仅因为有更好的做事方法,并不一定意味着应该删除语言功能。然后,您可以为许多其他语言结构辩护:for循环,goto等。