【问题标题】:Why does the "out" parameter exist in C# as a language construct? [closed]为什么“out”参数作为语言结构存在于 C# 中? [关闭]
【发布时间】:2019-02-18 00:37:58
【问题描述】:

问题

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

详细说明问题

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

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

难道没有更好的方法从一个方法返回多个值吗?

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

我没有问什么

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

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

预期答案格式

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

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

请不要发表意见。

【问题讨论】:

  • 根据定义,这个问题是基于意见的,这就是它被关闭的原因。
  • @DavidG:我不明白。这种意见的依据是什么?难道不能说,“看,这个问题只能通过使用'out'参数来解决,这是一个代码示例”?就像 KristoferA 在他的 answer? 中所做的那样?
  • 很明显,使用ref 可以获得相同的结果,只是不能保证参数会在方法内部初始化。这可能是 C# 设计团队的意见,添加这种支持会很好。但是,如果没有真正让 C# 语言团队的任何人回答这个问题,或者在其他地方链接到这样的答案,这里的所有答案都只是某人的意见。
  • 我不同意那些认为这是基于意见的人。我懒得花一个小时在谷歌上搜索它,但我打赌在这方面有来自 Hejlsberg 或 Lippert 的引述。
  • 词源学问题通常不适合 Stack Overflow,因为您确实在寻找某事的根本原因,而 我们 知道的根本原因就像 @利亚姆说,它在那里,因为规范说它在那里。你问为什么有人首先将它添加到规范中,这将需要这些人,正如 Jeroen 在上面发布的那样,让其中一个人发布明确答案的机会甚至不是不可能的。我们都可以提出它存在的充分理由,或者应该删除它的充分理由,但那些是意见。

标签: c# out


【解决方案1】:

C# 编译器执行definite assignment checking。这要求它准确知道何时分配变量。通常不难弄清楚,一项任务很容易看到。

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

所以你必须明确它,当方法需要在调用之前分配参数时使用ref,当方法只分配它时使用out。顺便说一句,很棒的功能,它消除了一整套非常常见的错误。


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

【讨论】:

  • 我想问一个关于最后一句话的问题。如果我将out 用于unsafe 上下文中的值对象,是否需要使用fixed 语句?
  • 该注释很难解析,从“值对象”开始。一般来说,不需要确保传递的对象不能被垃圾收集。 GC 在遍历堆栈时找到它。使用固定语句只生成一个指针。
  • 抱歉措辞不好。我的意思是:Afaik 允许 GC 将任何对象移动到另一个内存位置。如果我发送一个指向 pinvoke 调用的指针,我担心 GC 已将对象从指定的位置移开。
  • pinvoke marshaller 的基本职责之一是固定您通过的任何内容。就其本身而言,不需要帮助。如果您明确传递指针(不要),那么它确实成为您的工作。但是 C# 要求您使用 GCHandle 或固定语句来生成该指针,因此您不会弄错。我强烈建议您使用带有具体示例的按钮来了解更多信息。
【解决方案2】:

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

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

【讨论】:

【解决方案3】:

为什么它首先存在?难道没有更好的语言特性来获得与“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 解决方案也不会那么干净,但它仍然是一个更好的选择,而不是用大量的轻量级容器类乱扔代码库来简单地让方法返回多个值。

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

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

Aslo,你在这里搞混了。如果您想通过引用语义传递,您将使用 ref 关键字。 out 关键字表示该参数旨在用作返回值;它需要通过引用传递的事实是一个实现细节。

难道没有更好的方法从一个方法返回多个值吗?

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

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

向后兼容是显而易见的重要原因。此外,仅仅因为有更好的做事方式并不一定意味着应该删除语言特性。然后,您可以为许多其他语言结构提供案例:for 循环、goto 等。

【讨论】:

    猜你喜欢
    • 2017-07-31
    • 2018-06-19
    • 2018-03-22
    • 1970-01-01
    • 2014-01-09
    • 1970-01-01
    • 2014-02-11
    • 2018-10-22
    • 1970-01-01
    相关资源
    最近更新 更多