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

发布于 2024-07-27 14:11:20 字数 282 浏览 10 评论 0 原文

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

我见过这样的方法,

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

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

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

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.

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 ParseResult type? or in the newer framework return a null-able type?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

2024-08-03 14:11:20

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

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

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

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

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

而不是:

UpdateWithResult(DoSomething(5));

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

Out is good when you have a TryNNN function 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:

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.

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.

℉絮湮 2024-08-03 14:11:20

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

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

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:

bool isValid = int.TryParse("100", out int result = 0);
夜司空 2024-08-03 14:11:20

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

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

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

注意:

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

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

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.

Note:

  1. out params 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
节枝 2024-08-03 14:11:20

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

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.

那一片橙海, 2024-08-03 14:11:20

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

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

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

public int Do(int arg1, int arg2)

out 参数有一些好处:

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

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

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:

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:

public int Do(int arg1, int arg2)

There are some good things about out parameters:

  1. Output parameters are initially considered unassigned.
    • Every out parameter must be definitely assigned before the method returns, your code will not compile if you miss an assignment.

In conclusion, I basically try use out params in my private API to 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.

情何以堪。 2024-08-03 14:11:20

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

String strNum = "-1";
Int32 outNum;

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

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

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.

终陌 2024-08-03 14:11:20

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

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

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.

哎呦我呸! 2024-08-03 14:11:20

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

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

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

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.

夜夜流光相皎洁 2024-08-03 14:11:20

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

如此处所述,一个典型的用例是 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);
}

至于“为什么不返回 Nullable 类型”:TryParse 自 Framework 1.x 起就存在,而 Nullable 类型是在 2.0 中出现的(因为它们需要泛型)。 那么,为什么会不必要地破坏兼容性或开始在某些类型上的 TryParse 之间引入不一致呢? 您始终可以编写自己的扩展方法来复制已有的功能(请参阅 Eric Lipperts 发布在一个不相关的主题上,其中包括做/不做某事背后的一些推理)

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

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 TrySomething Method 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.

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 Post on an unrelated subject that includes some reasoning behind doing/not doing stuff)

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.

2024-08-03 14:11:20

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

StatusInfo a, b, c;

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

至少对我来说

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

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

I use out parameters 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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文