考虑一个返回两个值的函数。我们可以这样写:
// 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的输出参数。
Tuple会产生集合压力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 坐标,则这两个值语义上是相关的,最好使用一个 struct
。
个人建议不要在对外部代码可见的任何地方使用 tuple
,因为检索成员的语法很笨拙。
out
。此外,为了保持问题的简洁性,我没有提到 params
关键字。 - Xaqron没有所谓的“最佳实践”。重要的是你自己感觉舒适并且在你的情况下最有效的方法。只要你保持一致,那么你发布的任何解决方案都没有问题。
(int a, int b) DoSomething() {}
(int b, int a) result = DoSomething();
struct
。 - Xaqron