101

考虑一个返回两个值的函数。我们可以写:

// Using out:
string MyFunction(string input, out int count)

// Using Tuple class:
Tuple<string, int> MyFunction(string input)

// Using struct:
MyStruct MyFunction(string input)

哪一个是最佳实践,为什么?

4

6 回答 6

104

他们每个人都有自己的优点和缺点。

输出参数既快又便宜,但需要您传入一个变量,并依赖于变异。在 LINQ 中正确使用 out 参数几乎是不可能的。

元组创建收集压力1并且是非自记录的。“Item1”不是很具有描述性。

如果自定义结构很大,复制起来可能会很慢,但如果它们很小,则可以自我记录并且效率很高。然而,为琐碎的用途定义一大堆自定义结构也很痛苦。

我会倾向于自定义结构解决方案,所有其他条件都相同。更好的是创建一个只返回一个值的函数。你为什么首先返回两个值?

请注意,在编写此答案六年后发布的 C# 7 中的元组是值类型,因此不太可能产生收集压力。


1每次从堆中分配一个小对象时,都会对垃圾收集器施加“压力”。压力越大,收集越频繁。在某些应用程序中,控制产生的收集压力量很重要,因此在这些应用程序中不必要地分配几百万个元组可能是一件坏事。当然,就像所有关于性能的问题一样,在您了解问题的严重性之前,不要盲目地进行更改。

于 2011-06-17T06:07:45.297 回答
35

添加到前面的答案中,C# 7 带来了值类型元组,与System.Tuple引用类型不同,它还提供了改进的语义。

您仍然可以不命名它们并使用以下.Item*语法:

(string, string, int) getPerson()
{
    return ("John", "Doe", 42);
}

var person = getPerson();
person.Item1; //John
person.Item2; //Doe
person.Item3;   //42

但是这个新特性真正强大的是命名元组的能力。所以我们可以像这样重写上面的代码:

(string FirstName, string LastName, int Age) getPerson()
{
    return ("John", "Doe", 42);
}

var person = getPerson();
person.FirstName; //John
person.LastName; //Doe
person.Age;   //42

还支持解构:

(string firstName, string lastName, int age) = getPerson()

于 2017-06-06T11:44:05.560 回答
22

我认为答案取决于函数正在做什么的语义,以及两个值之间的关系。

例如,这些TryParse方法接受一个out参数来接受解析的值,并返回一个bool来指示解析是否成功。这两个值并不真正属于一起,因此,从语义上讲,它更有意义,代码的意图更易于阅读,使用out参数。

但是,如果您的函数返回屏幕上某个对象的 X/Y 坐标,那么这两个值在语义上属于一起,最好使用 a struct

我个人会避免将 atuple用于外部代码可见的任何内容,因为检索成员的语法很尴尬。

于 2011-06-17T06:08:01.157 回答
2

我将采用使用 Out 参数的方法,因为在第二种方法中,您需要创建 Tuple 类的对象,然后为其添加值,与在 out 参数中返回值相比,我认为这是一项昂贵的操作。虽然如果你想在元组类中返回多个值(实际上不能通过只返回一个输出参数来完成),那么我将采用第二种方法。

于 2011-06-17T06:09:38.363 回答
2

您没有再提到一个选项,即使用自定义类而不是结构。如果数据具有关联的语义,可以通过函数对其进行操作,或者实例大小足够大(根据经验,> 16 字节),则可能首选自定义类。不建议在公共 API 中使用“out”,因为它与指针关联并且需要了解引用类型的工作原理。

https://msdn.microsoft.com/en-us/library/ms182131.aspx

元组适合内部使用,但在公共 API 中使用起来很尴尬。所以,我的投票是在公共 API 的结构和类之间。

于 2016-08-31T17:44:02.583 回答
1

没有“最佳实践”。这是您感到满意的,并且在您的情况下最有效的方法。只要您对此保持一致,您发布的任何解决方案都没有问题。

于 2011-06-17T06:05:51.410 回答