C# 我什么时候应该使用 out 参数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1169786/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 09:55:57  来源:igfitidea点击:

When should I use out parameters?

c#.netout

提问by kay.one

I don't understand when an output parameter should be used, I personally wrap the result in a new type if I need to return more than one type, I find that a lot easier to work with than out.

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

I have seen method like this,

我见过这样的方法,

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

are there any cases where that actually makes sense?

有没有真正有意义的情况?

how about TryParse, why not return a ParseResulttype? or in the newer framework return a null-able type?

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

采纳答案by jasonh

Out is good when you have a TryNNNfunction and it's clear that the out-parameter will always be set even if the function does not succeed. This allows you rely on the fact that the local variable you declare will be set rather than having to place checks later in your code against null. (A comment below indicates that the parameter could be set to null, so you may want to verify the documentation for the function you're calling to be sure if this is the case or not.) It makes the code a little clearer and easier to read. Another case is when you need to return some data and a status on the condition of the method like:

当你有一个TryNNN函数时,输出很好,很明显,即使函数没有成功,输出参数也将始终被设置。这允许您依赖于您声明的局部变量将被设置这一事实,而不必稍后在您的代码中针对空值进行检查。(下面的注释表明该参数可以设置为null,因此您可能需要验证您正在调用的函数的文档,以确定是否是这种情况。)它使代码更清晰,更容易读。另一种情况是当您需要根据方法的条件返回一些数据和状态时,例如:

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

In this case the return can indicate if the function succeeded and the result is stored in the out parameter. Admittedly, this example is contrived because you can design a way where the function simply returns a string, but you get the idea.

在这种情况下,返回值可以指示函数是否成功并且结果存储在 out 参数中。诚然,这个例子是人为设计的,因为您可以设计一种方法,让函数简单地返回 a string,但您明白了。

A disadvantage is that you have to declare a local variable to use them:

一个缺点是你必须声明一个局部变量才能使用它们:

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

Instead of:

代替:

UpdateWithResult(DoSomething(5));

However, that may not even be a disadvantage, it depends on the design you're going for. In the case of DateTime, both means (Parse and TryParse) are provided.

但是,这甚至可能不是缺点,这取决于您要进行的设计。在 DateTime 的情况下,提供了两种方法(Parse 和 TryParse)。

回答by chikak

Creating a type just for returning values sounds little painful to me :-) First i will have to create a type for returning the value then in the calling method i have assign the value from the returned type to the actual variable that needs it.

创建一个仅用于返回值的类型对我来说听起来并不痛苦:-) 首先,我必须创建一个返回值的类型,然后在调用方法中,我将返回类型中的值分配给需要它的实际变量。

Out parameters are simipler to use.

输出参数使用起来更简单。

回答by David Anderson

Yes, it does make sense. Take this for example.

是的,确实有道理。以这个为例。

String strNum = "-1";
Int32 outNum;

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

What could you return if the operation failed in a normal function with a return value? You most certainly could not return -1 to represent a fail, because then there would be no differentiation between the fail-return value and the actual value that was being parsed to begin with. This is why we return a Boolean value to see if it succeeded, and if it did then we have our "return" value safely assigned already.

如果操作在带有返回值的普通函数中失败,你能返回什么?您肯定不能返回 -1 来表示失败,因为这样一来,失败返回值和开始解析的实际值之间就没有区别了。这就是为什么我们返回一个布尔值来查看它是否成功,如果成功,那么我们已经安全地分配了我们的“返回”值。

回答by Spencer Ruport

It does annoy me that I can't pass in null to the out parameter for the TryParse functions.

我无法将 null 传递给 TryParse 函数的 out 参数,这让我很恼火。

Still, I prefer it in some cases to returning a new type with two pieces of data. Especially when they're unrelated for the most part or one piece is only needed for a single operation a moment after. When I do need to save the resulting value of a TryParse function I really like having an out parameter rather than some random ResultAndValue class that I have to deal with.

不过,在某些情况下,我更喜欢返回带有两条数据的新类型。尤其是当它们大部分不相关或片刻之后仅需要单个操作时。当我确实需要保存 TryParse 函数的结果值时,我真的很喜欢有一个 out 参数,而不是我必须处理的一些随机 ResultAndValue 类。

回答by Gishu

Well as with most things it depends. Let us look at the options

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

  • you could return whatever you want as the return value of the function
  • if you want to return multiple values or the function already has a return value, you can either use out params or create a new composite type that exposes all these values as properties
  • 你可以返回任何你想要的作为函数的返回值
  • 如果你想返回多个值或者函数已经有一个返回值,你可以使用 out params 或创建一个新的复合类型,将所有这些值公开为属性

In the case of TryParse, using an out param is efficient - you dont have to create a new type which would be 16B of overhead (on 32b machines) or incur the perf cost of having them garbage collected post the call. TryParse could be called from within a loop for instance - so out params rule here.
For functions that would not be called within a loop (i.e. performance is not a major concern), returning a single composite object might be 'cleaner' (subjective to the beholder). Now with anonymous types and Dynamic typing , it might become even easier.

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

Note:

笔记:

  1. outparams have some rules that need to be followed i.e. the compiler will ensure that the function does initialize the value before it exits. So TryParse has to set the out param to some value even if parse operation failed
  2. The TryXXX pattern is a good example of when to use out params - Int32.TryParse was introduced coz people complained of the perf hit of catching exceptions to know if parse failed. Also the most likely thing you'd do in case parse succeeded, is to obtain the parsed value - using an out param means you do not have to make another method call to Parse
  1. outparams 有一些需要遵循的规则,即编译器将确保函数在退出之前确实初始化了该值。因此,即使解析操作失败,TryParse 也必须将输出参数设置为某个值
  2. TryXXX 模式是何时使用参数的一个很好的例子 - Int32.TryParse 被引入,因为人们抱怨捕获异常的性能命中以了解解析是否失败。如果 parse 成功,您最有可能做的事情是获取解析的值 - 使用 out 参数意味着您不必对 Parse 进行另一个方法调用

回答by devuxer

I think out is useful for situations where you need to return both a boolean and a value, like TryParse, but it would be nice if the compiler would allow something like this:

我认为 out 在需要返回布尔值和值的情况下很有用,例如 TryParse,但如果编译器允许这样的事情,那就太好了:

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

回答by Mark Cidade

I use outparameters sometimes for readability, when reading the method name is more important than whatever the output of the method is—particularly for methods that execute commands in addition to returning results.

我有时会使用out参数来提高可读性,当读取方法名称比方法的输出更重要时 - 特别是对于除了返回结果之外还执行命令的方法。

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);

At least for me, I put a lot of emphasis on the first few characters of each line when I'm scanning. I can easily tell what's going on in the first example after acknowledging that some "StatusInfo" variables are declared. In the second example, the first thing I see is that a bunch of StatusInfo is retrieved. I have to scan a second time to see what kind of effects the methods may have.

至少对我来说,我在扫描时非常重视每行的前几个字符。在确认声明了一些“StatusInfo”变量之后,我可以很容易地知道第一个示例中发生了什么。在第二个例子中,我看到的第一件事是检索了一堆 StatusInfo。我必须再次扫描,看看这些方法可能产生什么样的效果。

回答by Michael Stum

If you always create a type, then you can end up with a lot of clutter in your application.

如果你总是创建一个类型,那么你的应用程序最终可能会出现很多混乱。

As said here, one typical use case is a TrySomethingMethod where you want to return a bool as an indicator for success and then the actual value. I also find that a little bit cleaner in an if-statement - all three options roughly have the same LOC anyway.

正如这里所说,一个典型的用例是TrySomething方法,您希望返回一个 bool 作为成功的指标,然后返回实际值。我还发现在 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);
}

As for the "Why not return a Nullable Type": TryParse exists since Framework 1.x, whereas Nullable Types came with 2.0 (As they require Generics). So why unneccessarily break compatibility or start introducing inconsistencies between TryParse on some types? You can always write your own extension Method to duplicate functionality already existing (See Eric Lipperts Poston an unrelated subject that includes some reasoning behind doing/not doing stuff)

至于“为什么不返回 Nullable 类型”:TryParse 自 Framework 1.x 以来就存在,而 Nullable Types 随 2.0 一起出现(因为它们需要泛型)。那么为什么不必要地破坏兼容性或开始在某些类型的 TryParse 之间引入不一致呢?你总是可以编写你自己的扩展方法来复制已经存在的功能(参见Eric Lipperts Poston an unrelatedsubject,其中包括做/不做某事背后的一些推理)

Another use case is if you have to return multiple unrelated values, even though if you do that that should trigger an alarm that your method is possibly doing too much. On the other hand, if your Method is something like an expensive database or web service call and you want to cache the result, it may make sense to do that. Sure, you could create a type, but again, that means one more type in your application.

另一个用例是,如果您必须返回多个不相关的值,即使您这样做应该会触发警报,提示您的方法可能做得太多。另一方面,如果您的方法类似于昂贵的数据库或 Web 服务调用,并且您想要缓存结果,那么这样做可能是有意义的。当然,您可以创建一个类型,但同样,这意味着您的应用程序中还有一个类型。

回答by CMS

Definitely, out parameters are intended to be used when you have a method that needs to return more than one value, in the example you posted:

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

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

It doesn't makes much sense to use an out parameter, since you are only returning one value, and that method could be used better if you remove the out parameter and put a int return value:

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

public int Do(int arg1, int arg2)

There are some good things about out parameters:

out 参数有一些好处:

  1. Output parameters are initially considered unassigned.
    • Every out parameter mustbe definitely assigned before the method returns, your code will not compile if you miss an assignment.
  1. 输出参数最初被认为是未分配的。
    • 每个 out 参数必须在方法返回之前明确分配,如果您错过了分配,您的代码将无法编译。

In conclusion, I basically try use out params in my private APIto avoid creating separate types to wrap multiple return values, and on my public API, I only use them on methods that match with the TryParse pattern.

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

回答by ThomasVestergaard

Years late with an answer, I know. out (and ref as well) is also really useful if you do not wish your method do instantiate a new object to return. This is very relevant in high-performance systems where you want to achieve sub microsecond performance for your method. instantiating is relatively expensive seen from a memory access perspective.

我知道答案晚了好几年。如果您不希望您的方法实例化一个新对象以返回,out(以及 ref)也非常有用。这在您希望为您的方法实现亚微秒性能的高性能系统中非常重要。从内存访问的角度来看,实例化是相对昂贵的。