在 C# 中使用“out”关键字的最佳实践

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/413218/
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-04 02:26:28  来源:igfitidea点击:

Best practice of using the "out" keyword in C#

c#.net

提问by

I'm trying to formalise the usage of the "out" keyword in c# for a project I'm on, particularly with respect to any public methods. I can't seem to find any best practices out there and would like to know what is good or bad.

我正在尝试将 c# 中“out”关键字的使用形式化,用于我正在进行的项目,特别是对于任何公共方法。我似乎找不到任何最佳实践,想知道什么是好是坏。

Sometimes I'm seeing some methods signatures that look like this:

有时我会看到一些看起来像这样的方法签名:

public decimal CalcSomething(Date start, Date end, out int someOtherNumber){}

At this point, it's just a feeling, this doesn't sit well with me. For some reason, I'd prefer to see:

在这一点上,这只是一种感觉,这对我来说不太合适。出于某种原因,我更愿意看到:

public Result CalcSomething(Date start, Date end){}

where the result is a type that contains a decimal and the someOtherNumber. I think this makes it easier to read. It allows Result to be extended or have properties added without breaking code. It also means that the caller of this method doesn't have to declare a locally scoped "someOtherNumber" before calling. From usage expectations, not all callers are going to be interested in "someOtherNumber".

其中结果是包含小数和 someOtherNumber 的类型。我认为这使阅读更容易。它允许在不破坏代码的情况下扩展 Result 或添加属性。这也意味着此方法的调用者不必在调用之前声明本地范围的“someOtherNumber”。从使用预期来看,并非所有调用者都会对“someOtherNumber”感兴趣。

As a contrast, the only instances that I can think of right now within the .Net framework where "out" parameters make sense are in methods like TryParse(). These actually make the caller write simpler code, whereby the caller is primarily going to be interested in the out parameter.

相比之下,我现在能想到的在 .Net 框架中“out”参数有意义的唯一实例是在 TryParse() 之类的方法中。这些实际上使调用者编写更简单的代码,从而调用者主要对 out 参数感兴趣。

int i;
if(int.TryParse("1", i)){
  DoSomething(i);
}

I'm thinking that "out" should only be used if the return type is bool and the expected usages are where the "out" parameters will always be of interest to the caller, by design.

我认为只有当返回类型为 bool 并且预期的用法是调用者总是对“out”参数感兴趣时,才应该使用“out”。

Thoughts?

想法?

采纳答案by peSHIr

There is a reason that one of the static code analysis (=FxCop) rules points at you when you use outparameters. I'd say: only use outwhen really needed in interop type scenarios. In all other cases, simply do not use out. But perhaps that's just me?

当您使用out参数时,静态代码分析 (=FxCop) 规则之一指向您是有原因的。我会说:仅out在互操作类型场景中真正需要时才使用。在所有其他情况下,请不要使用out. 但也许这只是我?

回答by yfeldblum

Stay away from out. It's there as a low-level convenience. But at a high level, it's an anti-technique.

远离out. 它在那里是一种低级的便利。但在高层次上,这是一种反技术。

int? i = Util.TryParseInt32("1");
if(i == null)
    return;
DoSomething(i);

回答by Giovanni Galbo

Your approach is better than out, because you can "chain" calls that way:

你的方法总比外面好,因为你可以用这种方式“链接”调用:

DoSomethingElse(DoThing(a,b).Result);

as opposed to

DoThing(a, out b);
DoSomethingElse(b);

The TryParse methods implemented with "out" was a mistake, IMO. Those would have been very convenient in chains.

用“out”实现的 TryParse 方法是一个错误,IMO。这些在连锁店中会非常方便。

回答by James Curran

One advantage of outis that the compiler will verify that CalcSomethingdoes in fact assign a value to someOtherNumber. It will not verify that the someOtherNumber field of Result has a value.

的一个优点out是编译器将验证CalcSomething确实为 分配了一个值someOtherNumber。它不会验证 Result 的 someOtherNumber 字段是否有值。

回答by Treb

There are only very few cases where I would use out. One of them is if your method returns two variables that from an OO point of view do not belong into an object together.

只有极少数情况下我会使用out. 其中之一是如果您的方法返回从面向对象的角度来看不属于一个对象的两个变量。

If for example, you want to get the most common word in a text string, and the 42nd word in the text, you could compute both in the same method (having to parse the text only once). But for your application, these informations have no relation to each other: You need the most common word for statistical purposes, but you only need the 42nd word because your customer is a geeky Douglas Adams fan.

例如,如果您想获取文本字符串中最常见的单词和文本中的第 42 个单词,则可以使用相同的方法计算两者(只需解析文本一次)。但是对于您的应用程序,这些信息彼此无关:出于统计目的,您需要最常用的词,但您只需要第 42 个词,因为您的客户是 Douglas Adams 的极客粉丝。

Yes, that example is verycontrived, but I haven't got a better one...

是的,那个例子非常人为,但我没有更好的例子......

回答by Morten Christiansen

You could create a generic tuple class for the purpose of returning multiple values. This seems to be a decent solution but I can't help but feel that you lose a bit of readability by returning such a generic type (Resultis no better in that regard).

您可以创建一个通用元组类以返回多个值。这似乎是一个不错的解决方案,但我不禁觉得通过返回这样的泛型类型(Result在这方面没有更好),您会失去一些可读性。

One important point, though, that james curran also pointed out, is that the compiler enforces an assignment of the value. This is a general pattern I see in C#, that you must state certain things explicitly, for more readable code. Another example of this is the override keyword which you don't have in Java.

但是,james curran 还指出的一个重要点是编译器强制执行值的分配。这是我在 C# 中看到的一般模式,您必须明确说明某些事情,以获得更具可读性的代码。另一个例子是你在 Java 中没有的 override 关键字。

回答by Mitch Wheat

This is what the .NET Framework Developer's Guidehas to say about out parameters:

这是.NET Framework Developer's Guide关于 out 参数的说明:

Avoid using out or reference parameters.

Working with members that define out or reference parameters requires that the developer understand pointers, subtle differences between value types and reference types, and initialization differences between out and reference parameters.

避免使用 out 或 reference 参数。

使用定义输出或引用参数的成员要求开发人员了解指针、值类型和引用类型之间的细微差别以及输出和引用参数之间的初始化差异。

But if you do use them:

但是,如果您确实使用它们

Do place all out parameters after all of the pass-by-value and ref parameters (excluding parameter arrays), even if this results in an inconsistency in parameter ordering between overloads.

This convention makes the method signature easier to understand.

务必将所有 out 参数放在所有 pass-by-value 和 ref 参数(不包括参数数组)之后,即使这会导致重载之间的参数顺序不一致

这种约定使方法签名更容易理解。

回答by Tom Moseley

If your result is more complex than a single value, you should, if possible, create a result object. The reasons I have to say this?

如果您的结果比单个值更复杂,您应该尽可能创建一个结果对象。我要说这些的原因是什么?

  1. The entire result is encapsulated. That is, you have a single package that informs the code of the complete result of CalcSomething. Instead of having external code interpret what the decimal return value means, you can name the properties for your previous return value, Your someOtherNumber value, etc.

  2. You can include more complex success indicators. The function call you wrote might throw an exception if end comes before start, but exception throwing is the only way to report errors. Using a result object, you can include a boolean or enumerated "Success" value, with appropriate error reporting.

  3. You can delay the execution of the result until you actually examine the "result" field. That is, the execution of any computing needn't be done until you use the values.

  1. 整个结果被封装。也就是说,您有一个包来通知 CalcSomething 的完整结果的代码。您可以为之前的返回值、您的 someOtherNumber 值等命名属性,而不是让外部代码解释十进制返回值的含义。

  2. 您可以包含更复杂的成功指标。如果 end 在 start 之前,您编写的函数调用可能会抛出异常,但异常抛出是报告错误的唯一方法。使用结果对象,您可以包含布尔值或枚举的“成功”值,并带有适当的错误报告。

  3. 您可以延迟结果的执行,直到您实际检查“结果”字段。也就是说,在您使用这些值之前,不需要执行任何计算。

回答by phil soady

If you have even seen and worked with MS namespace System.Web.Security

如果您甚至见过并使用过 MS 命名空间 System.Web.Security

MembershipProvider 
   public abstract MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);

You will need a bucket. This is an example of a class breaking many design paradigms. Awful!

你需要一个水桶。这是一个打破许多设计范式的类的例子。可怕!

Just because the language has out parameters doesn't mean they should be used. eg goto

仅仅因为语言有参数并不意味着它们应该被使用。例如转到

The use of out Looks more like the Dev was either Lazy to create a type or wanted to try a language feature. Even the completely contrived MostCommonAnd42ndWordexample above I would use List or a new type contrivedresult with 2 properties.

使用 out 看起来更像是 Dev 要么懒惰地创建一个类型,要么想尝试一种语言功能。即使是MostCommonAnd42ndWord上面完全人为的示例,我也会使用 List 或具有 2 个属性的新类型人为结果。

The only good reasons i've seen in the explanations above was in interop scenarios when forced to. Assuming that is valid statement.

我在上面的解释中看到的唯一很好的原因是在被迫的互操作场景中。假设这是有效的陈述。

回答by aitchgee

I just had to add that starting from C# 7, the use of the out keywordmakes for very readable code in certain instances, when combined with inline variable declaration. While in general you should rather return a (named) tuple, control flow becomes very concise when a method has a boolean outcome, like:

我只需要补充一点,从 C# 7 开始,当与内联变量声明结合使用时,在某些情况下使用out 关键字可以使代码变得非常可读。虽然通常你应该返回一个(命名的)元组,但当方法具有布尔结果时,控制流变得非常简洁,例如:

if (int.TryParse(mightBeCount, out var count)
{
    // Successfully parsed count
}

I should also mention, that defining a specific class for those cases where a tuple makes sense, more often than not, is more appropriate. It depends on how many return values there are and what you use them for. I'd say, when more than 3, stick them in a class anyway.

我还应该提到,为那些元组有意义的情况定义一个特定的类,通常更合适。这取决于有多少返回值以及您使用它们的目的。我会说,当超过 3 个时,无论如何都要把它们放在一个班级里。