考虑一个返回两个值的函数。我们可以写:
// Using out:
string MyFunction(string input, out int count)
// Using Tuple class:
Tuple<string, int> MyFunction(string input)
// Using struct:
MyStruct MyFunction(string input)
哪一个是最佳实践,为什么?
考虑一个返回两个值的函数。我们可以写:
// Using out:
string MyFunction(string input, out int count)
// Using Tuple class:
Tuple<string, int> MyFunction(string input)
// Using struct:
MyStruct MyFunction(string input)
哪一个是最佳实践,为什么?
他们每个人都有自己的优点和缺点。
输出参数既快又便宜,但需要您传入一个变量,并依赖于变异。在 LINQ 中正确使用 out 参数几乎是不可能的。
元组创建收集压力1并且是非自记录的。“Item1”不是很具有描述性。
如果自定义结构很大,复制起来可能会很慢,但如果它们很小,则可以自我记录并且效率很高。然而,为琐碎的用途定义一大堆自定义结构也很痛苦。
我会倾向于自定义结构解决方案,所有其他条件都相同。更好的是创建一个只返回一个值的函数。你为什么首先返回两个值?
请注意,在编写此答案六年后发布的 C# 7 中的元组是值类型,因此不太可能产生收集压力。
1每次从堆中分配一个小对象时,都会对垃圾收集器施加“压力”。压力越大,收集越频繁。在某些应用程序中,控制产生的收集压力量很重要,因此在这些应用程序中不必要地分配几百万个元组可能是一件坏事。当然,就像所有关于性能的问题一样,在您了解问题的严重性之前,不要盲目地进行更改。
添加到前面的答案中,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()
我认为答案取决于函数正在做什么的语义,以及两个值之间的关系。
例如,这些TryParse
方法接受一个out
参数来接受解析的值,并返回一个bool
来指示解析是否成功。这两个值并不真正属于一起,因此,从语义上讲,它更有意义,代码的意图更易于阅读,使用out
参数。
但是,如果您的函数返回屏幕上某个对象的 X/Y 坐标,那么这两个值在语义上属于一起,最好使用 a struct
。
我个人会避免将 atuple
用于外部代码可见的任何内容,因为检索成员的语法很尴尬。
我将采用使用 Out 参数的方法,因为在第二种方法中,您需要创建 Tuple 类的对象,然后为其添加值,与在 out 参数中返回值相比,我认为这是一项昂贵的操作。虽然如果你想在元组类中返回多个值(实际上不能通过只返回一个输出参数来完成),那么我将采用第二种方法。
您没有再提到一个选项,即使用自定义类而不是结构。如果数据具有关联的语义,可以通过函数对其进行操作,或者实例大小足够大(根据经验,> 16 字节),则可能首选自定义类。不建议在公共 API 中使用“out”,因为它与指针关联并且需要了解引用类型的工作原理。
https://msdn.microsoft.com/en-us/library/ms182131.aspx
元组适合内部使用,但在公共 API 中使用起来很尴尬。所以,我的投票是在公共 API 的结构和类之间。
没有“最佳实践”。这是您感到满意的,并且在您的情况下最有效的方法。只要您对此保持一致,您发布的任何解决方案都没有问题。