我不明白何时应该使用输出参数,如果我需要返回多个类型,我个人会将结果包装在新类型中,我发现使用它比使用 out 更容易。

我见过这样的方法,

   public void Do(int arg1, int arg2, out int result)

在某些情况下这实际上是有意义的吗?

怎么样 TryParse, ,为什么不返回一个 ParseResult 类型?或者在较新的框架中返回一个可以为空的类型?

有帮助吗?

解决方案

Out是好当你有一个TryNNN功能,很明显的是,从参数将始终,即使该函数没有成功设置。这可以让你依靠的事实,你声明的局部变量将被设置,而不是后来把支票在你对空代码。 (下面留言表示该参数可以设置为null,所以你可能要验证你打电话,以确保如果是这种情况或不函数的文档)。这使得代码更清晰一点,更容易读书。另一种情况是,当你需要返回上的方法的条件的一些数据和一个状态,如:

public bool DoSomething(int arg1, out string result);

在这种情况下,返回可以指示如果函数成功且结果被存储在输出参数。诚然,这个例子是人为的,因为你可以设计一种在函数返回一个string,但你的想法。

一个缺点是,必须声明一个局部变量来使用它们:

string result;
if (DoSomething(5, out result))
    UpdateWithResult(result);

代替:

UpdateWithResult(DoSomething(5));

然而,这甚至可能不是一个缺点,它取决于你要去的设计。在日期时间的情况下,两个装置(解析和的TryParse)被提供。

其他提示

与大多数事情一样,这取决于情况。让我们看看选项

  • 你可以返回任何你想要的作为函数的返回值
  • 如果您想返回多个值或函数已经有返回值,您可以使用 out params 或创建一个新的复合类型,将所有这些值公开为属性

在 TryParse 的情况下,使用 out 参数是高效的 - 您不必创建一个新类型,这将是 16B 的开销(在 32b 机器上),也不必承担在调用后对它们进行垃圾收集的性能成本。例如,TryParse 可以从循环内调用 - 所以这里的参数规则。
对于不会在循环内调用的函数(即性能不是主要问题),返回单个复合对象可能会“更干净”(对观看者来说是主观的)。现在有匿名类型 和动态类型,它可能会变得更加容易。

笔记:

  1. out params 有一些需要遵循的规则,即编译器将确保函数在退出之前确实初始化该值。因此,即使解析操作失败,TryParse 也必须将输出参数设置为某个值
  2. TryXXX 模式是何时使用参数的一个很好的例子 - Int32.TryParse 的引入是因为人们抱怨捕获异常以了解解析是否失败的性能。另外,如果解析成功,您最有可能做的事情是获取解析的值 - 使用输出参数意味着您不必对 Parse 进行另一个方法调用

我想出来是你需要同时返回一个布尔值和值,像的TryParse情况下非常有用,但它会是不错的,如果编译器会允许这样的事情:

bool isValid = int.TryParse("100", out int result = 0);

当然,当您有一种需要返回多个值的方法时,应使用 out 参数,在您发布的示例中:

public void Do(int arg1, int arg2, out int result)

使用 out 参数没有多大意义,因为您只返回一个值,如果删除 out 参数并放入 int 返回值,则可以更好地使用该方法:

public int Do(int arg1, int arg2)

out 参数有一些好处:

  1. 输出参数最初被视为未分配。
    • 每个输出参数 必须 在方法返回之前明确分配,如果错过分配,您的代码将无法编译。

总之,我基本上尝试在我的 私有API 为了避免创建单独的类型来包装多个返回值,并且在我的公共 API 上,我仅在与 TryParse 模式匹配的方法上使用它们。

迟到一个答案

十年来,我知道。 出(和ref以及)也是非常有用的,如果你不希望你的方法做实例化一个新的对象返回。这是要实现你的方法亚微秒性能的高性能系统非常重要。实例化是相对昂贵看到从存储器存取的视角。

创建类型只是返回值听起来有点痛苦给我:-) 首先,我将不得不在调用方法我从返回类型需要它的实际变量赋值,然后返回值创建一个类型。

输出参数是simipler使用。

是的,这有一定道理。借此例如

String strNum = "-1";
Int32 outNum;

if (Int32.TryParse(strNum, out outNum)) {
    // success
}
else {
    // fail
}

你能返回如果操作与返回值的正常功能失败了吗?你肯定无法返回-1代表失败,因为那时会有故障返回值,这是被解析开始与实际值之间没有区别。这就是为什么我们返回一个布尔值,看它是否成功,如果它没有那么我们有我们的“回归”安全值已经分配。

它烦扰我,我不能在空传递给该功能的TryParse OUT参数。

不过,我喜欢它在某些情况下与两个数据返回一个新的类型。尤其是当他们是不相关的大部分或只需要片刻后单次操作一件。当我需要真正保存生成的一个函数的TryParse我的价值就像一出参数,而不是一些随机ResultAndValue类,我不得不处理。

如果你总是创建一个类型,那么你就可以在你的应用程序有很多杂乱的结束。

由于在这里说,一个典型的使用情况是要返回一个布尔值作为成功与否的指标,然后将实际值TrySomething方法。我还发现,在if语句一点点清洁 - 所有三个选项大致有相同的LOC反正

int myoutvalue;
if(int.TryParse("213",out myoutvalue){
    DoSomethingWith(myoutvalue);
}

vs.

ParseResult<int> myoutvalue = int.TryParse("213");
if ( myoutvalue.Success ) {
    DoSomethingWith(myoutvalue.Value);
}

vs.

int? myoutvalue = int.TryParse("213");
if(myoutvalue.HasValue){
    DoSomethingWith(myoutvalue.Value);
}

至于“为什么不返回一个空类型”:自的TryParse框架1.x中存在,而空类型2.0来了(因为它们需要仿制药)。那么,为什么会不必要破坏兼容性或开始在某些类型的引入的TryParse之间的不一致?你总是可以编写自己的扩展方法来复制功能已经存在(见的上不相关的主题,其包括后面做一些推理埃里克Lipperts帖子 /不这样做的东西)

另一个用例是,如果你要返回多个不相关的值,即使如果你这样做应该触发报警,你的方法可能是做得太多。在另一方面,如果你的方法是像一个昂贵的数据库或Web服务调用,并要缓存的结果,它可能是有意义的做到这一点。当然,你可以创建一个类型,但同样,这意味着在应用程序中多了一个类型。

我使用的有时为了可读性参数,读取方法名称时比任何方法的输出是-特别是对于执行除了命令来返回结果的方法更重要。

StatusInfo a, b, c;

Initialize(out a);
Validate(a, out b);
Process(b, out c);

VS

StatusInfo a = Initialize();
StatusInfo b = Validate(a);
StatusInfo c = Process(b);

至少对我来说,我把很多重点就当我在扫描每一行的前几个字符。我可以很容易地分辨承认,一些“StatusInfo”变量声明之后发生的事情在第一个例子。在第二个例子中,我看到的第一件事是一堆StatusInfo的检索。我必须扫描第二次看的方法可以有什么样的影响。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top