Mad*_*mon 55 c# tuples c#-7.0 valuetuple
在Tuples之前,我曾经创建一个class
及其变量,然后从这个类创建对象,并使该对象成为某些函数的返回类型.
现在用的元组,我可以做同样的在C#7.0,我们可以将元组性质可以理解的名称(这是之前item1
,item2
等..)
所以现在我想知道,我应该何时使用元组,何时应该在c#7.0中创建一个类?
Dav*_*rno 40
由于这个答案在这里引起了一些人的混淆,我应该澄清 - 根据问题 - 这里所有对"元组"的引用都是指ValueTuple
C#7 的类型和新元组语法糖特征,绝不是指旧的System.Tuple
参考类型.
所以现在我想知道,我什么时候应该使用元组?什么时候应该在c#7.0中创建一个类?
只有你能真正回答这个问题,因为它真的取决于你的代码.
但是,您可以遵循指导和规则来指导您在它们之间进行选择:
大多数时候,这应该不是问题.但是,如果您传递大型结构的元组,这可能会对性能产生影响.但是,参考本地/返回可用于解决这些性能问题.
此外,因为它们是值,远程修改副本不会更改原始副本.这是一件好事,但可以抓住一些人.
编译器使用赋予元素的名称,并且(在大多数情况下)在运行时不可用.这意味着反射不能用于发现他们的名字; 它们无法动态访问,也无法在剃刀视图中使用.
这也是API的一个重要考虑因素.从方法返回的元组是关于编译后名称可发现性的规则的例外.编译器将属性添加到保存元组名称信息的方法.这意味着您可以安全地从一个程序集中的公共方法返回一个元组,并在另一个程序集中访问它的名称.
编写比类型更简单,因为它们不那么详细,并且声明可以"内联"(即在使用时声明).例如,在声明返回多个值的方法时,这很有效.
但是,因为它们是在使用点声明的,如果你有MethodA
调用的MethodB
调用MethodC
并且每个调用返回一个元组,你需要在每个阶段重新定义元组.没有(还)创建一个元组的别名,并重新使用它跨多个方法的方法.
对于您可能考虑使用元组的任何情况:只需问自己一个问题:"元组是否会简化代码".如果答案是"是",那么使用一个.这最终是关于是使用元组还是自定义类的主要考虑因素.
Gus*_*dor 20
一般来说,命名类在系统设计中具有一定的意义.他们写作也比较冗长.例如,您可能有一个名为的类MediaFileOpener
.设计我们知道这个课程的作用非常重要 - 我们正在使用媒体文件!
当没有设计意义并且您想要的只是一个轻量级数据传输对象(DTO)来移动信息时,将使用匿名类型和元组.
按规则,如果您的类需要一些文档来描述它的用途,或者是否存在它提供的行为,请使用完整的类.如果您只需要临时存储或某种分组,请使用元组.考虑一种情况,您希望从异步方法返回多个值.元组旨在解决这个问题.
使用班级
如果您的对象是在整个应用程序中广泛使用的实体,并且还存储在某种持久存储中,如关系数据库(SQL Server,MySQL,SQLite),NoSQL数据库或缓存(Redis,Azure DocumentDB),甚至是简单的文本文件或CSV.
所以,任何持久的东西都应该有自己的类.
使用元组
如果您的对象是短暂的,对您的应用没有特殊意义.例如,如果你需要快速返回一对坐标,最好有这样的东西:
(double Latitude, double Longitude) getCoordinates()
{
return (144.93525, -98.356346);
}
Run Code Online (Sandbox Code Playgroud)
而不是定义一个单独的类
class Coordinates
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
new
对于这样一个简单的操作,元组将节省您在堆上分配内存的时间.
另一个我发现元组有用的时候是对某些操作数执行多个数学运算
(double Result1, double Result2, double Result3) performCalculations(int operand1, int operand 2)
Run Code Online (Sandbox Code Playgroud)
在这种情况下定义一个类是没有意义的.无论计算结果如何,结果都不属于某一类.所以替代方案是使用out
变量,但我相信元组更具表现力,并提高可读性.
通常,当您的对象将在其他地方使用时,或者如果它代表您的域中的真实对象或概念时,您希望拥有一个类。您可能要创建一个类来表示汽车或汽车商店,而不是元组。
另一方面,有时您只想从方法中返回几个对象。也许它们并不代表什么特别的东西,只是你需要在那个特定的方法中将它们一起返回。有时,即使它们确实代表了您领域中的一个概念(假设您要返回(Car, Store)
,它可以表示为一个Sale
对象),您实际上也不会在任何地方使用它们——您只是在移动数据。在这些情况下,可以使用元组。
现在,具体来说说 C#,还有一件事你应该知道。C# 7 的元组类型实际上是ValueTuple
,它是一个结构体。与作为引用类型的类不同,结构是值类型。您可以在msdn上阅读更多相关信息。最重要的是,要知道它们可能涉及大量复制,所以要小心。
我想首先提到 C# 已经支持匿名类型。哪些是引用类型。因此,您已经有了一个合适的替代方案来创建命名类。
\n命名类的优点之一是更容易重用(例如,如果您在多个位置需要相同的类型)和文档。由于匿名类型是匿名的,因此只有在可以使用的情况下才能获取输入到它的变量var
,则只能获取键入的变量,这限制了匿名类型有用的上下文(例如,不能将它们用作字段类型、返回类型或参数类型) )。
当然,您可以通过使用来克服匿名类型的一些限制System.Tuple
。这也是一个引用类型,您可以显式地使用它。缺点是它缺乏成员的自定义名称。
C# 7 元组 (ValueTuple
) 可以被视为类似于匿名类型。第一个区别是它们是值类型。这意味着这些元组只要保留在本地范围内或在堆栈中移动(由于其限制,这是匿名类型的常见用法),它们就会具有性能优势。
第二个区别是,新语法允许元组出现在比匿名类型更多的地方,如您所知,您有语法糖来定义返回类型ValueTuple
(当使用匿名类型时,您必须返回object
)。
第三个区别是ValueTuple
支持开箱即用的解构。引用C# 7.0 中的新功能 What\xe2\x80\x99s:
\n\n使用元组的另一种方法是解构它们。解构声明是一种将元组(或其他值)拆分为多个部分并将这些部分单独分配给新变量的语法:
\nRun Code Online (Sandbox Code Playgroud)\n(string first, string middle, string last) = LookupName(id1); // deconstructing declaration\nWriteLine($"found {first} {last}.");\n
您还可以通过添加Deconstruct 方法来处理自定义类型。
\n对于摘要:
\nValueTuple
C# 7.0 中有语法糖,应考虑可读性。ValueTuple
是一个值类型。使用 aclass
和 a之间的所有优点和缺点struct
之间的所有优点和缺点都适用。ValueTuple
可以明确使用(有或没有语法糖),使其具有以下多功能性System.Tuple
同时保留命名成员。ValueTuple
支持解构。鉴于它必须是语法糖,我想说选择的更强论据ValueTuple
与选择一个的论据相同struct
。这对于小型、不可变的类型来说是理想的选择,这些类型主要存在于堆栈中(因此您不需要进行大量的装箱和拆箱)。
ValueTuple
与完整的结构相比,考虑到语法糖,我建议默认使用,ValueTuple
除非您需要显式布局或需要向其添加方法。
我还想说,语法糖并不一定能提高可读性。主要原因是您没有命名类型,并且类型的名称为代码提供了含义。除此之外,您可以将文档添加到struct
或class
声明中以方便理解。
总而言之,ValueTuple
真正出色的情况是从一个方法返回多个值。在这种情况下,无需创建新out
参数。并且所使用的文档ValueTuple
可以存在于该方法的文档中。如果您发现需要使用其他方法ValueTuple
(例如定义扩展方法),我建议您考虑创建命名类型。
我认为这将成为一个经常被问到的问题。目前还没有关于何时使用新值元组与类的“最佳实践”。
然而,值得阅读之前关于元组与类的先前版本的对话中出现的内容。
在我看来,值元组应该只使用最少的值,并且最多不超过三个值。我认为这在“不需要类的情况下返回一些值”和“可怕的混乱的值”之间取得了很好的平衡。如果要返回三个以上的值,请创建一个类。
我也永远不会使用元组从消费者必须使用的面向公众的 API 返回。再次强调,只需使用一个类即可。
这是我使用过的一些现实世界的代码:
public async Task<(double temperature, double humidity, string description)> DownloadTodaysForecast()
Run Code Online (Sandbox Code Playgroud)
一旦我想返回更复杂的数据,我就会创建一个类。
归档时间: |
|
查看次数: |
16825 次 |
最近记录: |