在Tuples之前,我曾经创建一个class
,然后它的变量从这个类创建对象,并使该对象成为某些函数的返回类型。
现在有了元组,我可以做同样的事情,在c#7.0中,我们可以为元组属性分配可理解的名称(在此之前它是item1
,item2
等。)
所以现在我想知道,我应该何时使用元组,何时应该在c#7.0中创建一个类?
答案 0 :(得分:33)
由于这个答案在这里引起了一些人的混淆,我应该澄清 - 按照这个问题 - 所有提及"元组"这里引用C#7的ValueTuple
类型和新元组语法糖特性,绝不参考旧的System.Tuple
引用类型。
所以现在我想知道,我什么时候应该使用元组?什么时候应该在c#7.0中创建一个类?
只有你能真正回答这个问题,因为它真的取决于你的代码。
但是,您可以遵循指导原则和规则来指导您选择它们:
大多数时候,这应该不是问题。但是,如果您传递大型结构的元组,这可能会对性能产生影响。但是,参考本地/返回可用于解决这些性能问题。
此外,由于它们是值,因此远程修改副本不会更改原始副本。这是一件好事,但可以抓住一些人。
编译器使用赋予元素的名称,并且(在大多数情况下)在运行时不可用。这意味着反射不能用于发现他们的名字;它们无法动态访问,也无法在剃刀视图中使用。
这也是API的一个重要考虑因素。从方法返回的元组是关于编译后名称可发现性的规则的例外。编译器将属性添加到保存元组名称信息的方法。这意味着您可以安全地从一个程序集中的公共方法返回一个元组,并在另一个程序集中访问它的名称。
元组的编写要比类型简单得多,因为它们不那么详细,而且声明可以是#34; inlined" (即在使用点宣布)。例如,在声明返回多个值的方法时,这很有效。
但是,因为它们是在使用时声明的,如果您MethodA
调用MethodB
来调用MethodC
并且每个都返回一个元组,那么您需要在每个阶段重新定义元组。没有(yet)一种创建元组别名并在多种方法中重用它的方法。
对于您可能考虑使用元组的任何情况:只需问自己一个问题:"元组是否会在这里简化代码"。如果答案是"是",那么使用一个。这最终是关于是使用元组还是自定义类的主要考虑因素。
答案 1 :(得分:18)
一般来说,命名类在系统设计中具有一定的意义。他们写作也比较冗长。例如,您可能有一个名为<p>To quickly input an invalid date, select the day field and press the down arrow. This will select 31/06/2017 and output the desired invalid date string.</p>
<form><input type="date" value="2017-06-01"><output></output></form>
的类。设计我们知道这个课程的作用非常重要 - 我们正在使用媒体文件!
当没有设计意义并且你想要的只是一个轻量级的数据传输对象(DTO)来移动信息时,就会使用匿名类型和元组。
按规则,如果您的类需要一些文档来描述它的用途,或者是否存在它提供的行为,请使用完整的类。如果您只需要临时存储或某种分组,请使用元组。考虑一种情况,您希望从异步方法返回多个值。元组旨在解决这个问题。
答案 2 :(得分:8)
使用课程
如果您的对象是在整个应用程序中广泛使用的实体,并且还存储在某种持久存储中,如关系数据库(SQL Server,MySQL,SQLite),NoSQL数据库或缓存(Redis,Azure DocumentDB)或即使是简单的文本文件或CSV。
所以是的,任何持久的东西都应该有自己的类。
使用元组
如果您的对象是短暂的,对您的应用没有特殊意义。例如,如果你需要快速返回一对坐标,最好有这样的东西:
(double Latitude, double Longitude) getCoordinates()
{
return (144.93525, -98.356346);
}
而不是定义一个单独的类
class Coordinates
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
使用new
进行如此简单的操作,元组将节省您在堆上分配内存的时间。
另一次,当我发现元组有用时,是对某些操作数执行多个数学运算
(double Result1, double Result2, double Result3) performCalculations(int operand1, int operand 2)
在这种情况下定义一个类是没有意义的。无论计算结果如何,结果都不属于某一类。所以替代方案是使用out
变量,但我相信元组更具表现力并且可以提高可读性。
答案 3 :(得分:3)
首先我要提到C#已经支持anonymous types。哪些是参考类型。因此,您已经有了创建命名类的合适替代方法。
命名类的一个优点是将更容易重用(例如,如果您需要在多个位置使用相同的类型)和文档。由于匿名类型是匿名的,如果可以使用var
,则只能获取键入的变量,这限制了匿名类型有用的上下文(例如,您不能将它们用作字段类型,返回类型或参数类型)。
当然,您可以使用System.Tuple
来解决匿名类型的一些限制。这也是一种引用类型,您可以明确地使用它。缺点是缺乏成员的自定义名称。
C#7元组(ValueTuple
)可以被认为类似于匿名类型。第一个区别是它们是价值类型。这意味着只要这些元组保留在本地范围内或者在栈中移动(这是匿名类型的常见用法,由于其局限性),这些元组将具有性能优势。
第二个区别是新语法允许元组出现在比匿名类型更多的位置,正如您所知,您有语法糖来定义返回类型为ValueTuple
(使用匿名类型时必须返回object
)。
第三个区别是ValueTuple
支持开箱即用的解构。引用What’s New in C# 7.0:
消费元组的另一种方法是解构它们。解构声明是将元组(或其他值)拆分为其部分并将这些部分分别分配给新变量的语法:
(string first, string middle, string last) = LookupName(id1); // deconstructing declaration WriteLine($"found {first} {last}.");
您还可以通过添加Deconstruct method来自定义类型。
抽象:
ValueTuple
在C#7.0中具有语法糖,应考虑其可读性。ValueTuple
是值类型。使用class
和struct
之间的所有利弊都适用。ValueTuple
可以明确地使用(有或没有语法糖),允许它具有System.Tuple
的多功能性,同时保留命名成员。ValueTuple
支持解构。鉴于它必须是语法糖,我会说选择ValueTuple
的更强有力的论据是选择struct
的相同论点。这对于小型,不可变类型来说是理想的,它们主要存在于堆栈中(因此您没有大量的装箱和拆箱)。
比较ValueTuple
与完整的结构,考虑到语法糖,我建议默认使用ValueTuple
,除非您需要explicit layout或者需要添加方法
我还想说语法糖不一定能提高可读性。主要原因是您没有命名类型,并且类型的名称为代码提供了含义。除此之外,您还可以向struct
或class
声明添加文档,以便于理解。
总而言之,ValueTuple
真正发光的情况是从方法返回多个值。在这种情况下,无需创建新的out
参数。所使用的ValueTuple
的文档可以存在于该方法的文档中。如果您发现需要使用ValueTuple
(例如定义扩展方法)做其他事情,我建议您考虑创建一个命名类型。
答案 4 :(得分:2)
元组旨在表示多个值,例如方法要返回多个值时。 C#7 中的元组支持使用System.ValueTuple<...>
个实例来表示该组值。这些值的名称仅在使用它们的上下文中有效且不会强制执行。
类旨在表示具有多个属性的单个值。
答案 5 :(得分:2)
通常,当您的对象将在其他地方使用时,或者如果它代表您域中的真实对象或概念时,您希望拥有一个类。你可能会创建一个代表汽车或汽车商店的课程,而不是元组。
另一方面,有时您只想从方法中返回几个对象。也许他们不代表什么特别的东西,只是你需要用这种特殊方法将它们归还在一起。有时候,即使他们确实代表了您网域中的某个概念(比如说您正在返回(Car, Store)
,可以表示为Sale
个对象),您实际上并不会使用他们在任何地方 - 你只是移动数据。在这些情况下,使用元组很好。
现在,具体谈到C#,还有一件事你应该知道。 C#7的元组类型实际上是ValueTuple
,它是一个结构。与作为引用类型的类不同,结构是值类型。您可以在msdn上详细了解相关信息。最重要的是,要知道它们可能涉及大量复制,所以要小心。
答案 6 :(得分:1)
当您想要将多个值(可以是不同类型)组合到一个对象中而不创建自定义类时,元组是一个很好的选择。在这种情况下,Tuple将是一个快速而完美的选择。
答案 7 :(得分:0)
我认为这将成为一个被问到很多的问题。目前没有&#34;最佳做法&#34;何时使用新值元组与类。
但是,值得一读what came up during previous conversations about the previous versions of tuples vs a class。
在我看来,值元组应该只使用最少且不超过最多三个值。我认为这可以很好地平衡&#34;返回一些值而不需要一个类&#34;和#34;可怕的价值观混乱&#34;。如果您要返回三个以上的值,请创建一个类。
我也从不使用元组从消费者必须使用的面向公众的API返回。再次,只需使用一个类。
这是我使用的一些真实世界代码:
public async Task<(double temperature, double humidity, string description)> DownloadTodaysForecast()
只要我想返回更复杂的数据,我就会上课。
答案 8 :(得分:0)
我会避免使用元组作为返回类型的公共方法。在这种情况下,我更喜欢定义一个类或结构。
答案 9 :(得分:0)
答案 10 :(得分:0)
对于只使用一次的快速代码段,请使用元组。如果必须维护代码,请使用类。查看代码并看到以下表达式令人沮丧:
if (t.Item4 == x.Item3)