元组旨在解决什么要求?


94

我正在查看元组的新C#功能。我很好奇,元组旨在解决什么问题?

您在应用程序中使用了元组做什么?

更新资料

感谢您到目前为止的回答,让我看看我是否脑子里有很多东西。指出了元组的一个很好的例子作为坐标。这看起来正确吗?

var coords = Tuple.Create(geoLat,geoLong);

然后像这样使用元组:

var myLatlng = new google.maps.LatLng("+ coords.Item1 + ", "+ coords.Item2 + ");

那是对的吗?



4
好吧,我能想到两个答案……
午间丝绸

13
如果将“坐标”的概念作为一个班级有意义,那么我将其设为一个班级。对于没有合理的“业务逻辑”概念的数据集来证明建立类型的理由,请使用元组。
埃里克·利珀特

13
坐标不是元组的一个很好的例子。如果必须(从函数中)返回两个值,则C#中的元组只是临时解决方案。与其设置一个结果类型加一个out参数,不如返回一个元组。这样,您不必预先声明第二个参数。在C ++中,差异更加明显(您可以常量化结果,但不能常量out / ref参数)。
greenoldman 2010年

8
因为python拥有了它,而python不能拥有C#没有的任何东西;)
Evan Plaice 2010年

Answers:


117

在编写程序时,通常希望将一组值缺乏逻辑通用性的逻辑分组在一起,以证明创建一个类是合理的。

许多编程语言允许您在逻辑上将一组其他不相关的值组合在一起,而无需仅通过一种方式创建类型:

void M(int foo, string bar, double blah)

从逻辑上讲,这与方法M完全相同,该方法M接受一个参数,该参数是int,string,double的三元组。但我希望您实际上不会:

class MArguments
{
   public int Foo { get; private set; } 
   ... etc

除非MArguments在业务逻辑中具有其他含义。

“在一些结构中,将比类轻的一些结构中的其他不相关的数据组合在一起”的概念在很多地方很有用,而不仅仅是方法的正式参数列表。当方法要返回两件事时,或者您要从两个数据而不是一个数据中键入字典时,此方法很有用。

像F#这样的语言本身就支持元组类型,为用户提供了极大的灵活性。它们是一组非常有用的数据类型。BCL团队决定与F#团队合作,为框架定义一种元组类型,以便每种语言都可以从中受益。

但是,在这一点上,C#中没有对元组的语言支持。元组只是其他框架类中的另一种数据类型。他们没有什么特别的。我们正在考虑在假设的C#未来版本中为元组添加更好的支持。如果有人对您希望看到的涉及元组的功能有什么想法,我很乐意将它们传递给设计团队。现实情况比理论上的想法更具说服力。


1
@MalcomTucker:异步和并行性无疑是我们可以用语言工具解决实际问题的丰富领域。我认为F#风格的异步工作流不一定最适合C#,但它们确实鼓舞人心。
埃里克·利珀特

60
尽管元组很有用,但一大缺点是清晰度。这是难以阅读和理解,是指代码Item1Item2等等......如果元组永远做实现C#语言的支持,这将是美妙的,以允许以允许代码被命名为他们的成员(或至少化名)使用他们更容易理解。在这样一个假想的未来,我也很乐意将具有适当“形状”的元组视为采用单个参数的方法的合法参数(反之亦然)。因此,Tuple<int,string,bool>可以传递给M(int,string,bool)。这将使记忆方法更加容易。
LBushkin

2
这些“元组”基本上都是带有未命名成员的匿名public访问类型。我宁愿程序员编写一个带有命名成员的a并返回该成员,而不是不得不处理一个不告诉我有关其成员语义的东西。 structstructtuple
bobobobo

1
@ Hi-Angel:该论点不是要争论什么是元组,什么不是元组,而是关于现代业务线开发人员可以用来提高生产率的一组功能。LBushkin表示设计团队一直在听的功能请求:想要制作某种“记录类型”而又没有麻烦和花钱让整个班级仅容纳几个领域的麻烦。C#已经为方法提供了此功能;它称为“参数列表”。
埃里克·利珀特

2
@ Hi-Angel:您可能不会输入参数“如果要通过名称访问方法参数,则应创建一个单独的类”,因为这看起来非常繁琐,但仅因为我们习惯于使用在调用方法时能够立即将一组具有任意类型和名称的任意变量连接在一起的能力。想象没有语言具有该功能;每个方法只能有一个参数,如果要传递两个参数,则必须创建一个类型并传递一个实例。
Eric Lippert 2015年

22

元组提供集合的不变实现

除了元组的常见用法外:

  • 无需创建类即可将通用值分组在一起
  • 从函数/方法返回多个值
  • 等等...

不可变对象本质上是线程安全的:

不可变对象在多线程应用程序中可能很有用。多个线程可以对不可变对象表示的数据进行操作,而不必担心数据会被其他线程更改。因此,不可变对象被认为比可变对象更具线程安全性。

摘自维基百科上的“不可变对象”


感谢您为问题添加其他信息。非常感激。
Chaddeus

如果要一个不可变的集合,则应使用一个不可变的集合,而不是元组。区别在于,对于大多数不可变的集合,您无需在编译时指定元素的数量
BlueRaja-Danny Pflughoeft 2014年

@ BlueRaja-DannyPflughoeft回到我编写此答案时,BCL中C#不可变集合类仍然不可用。猜猜我会把“集合”更改为“对象”,因为MS截断了C#中的元组实现
Evan Plaice 2014年

12

它提供了一种替代方法,ref或者out如果您有一个方法需要返回多个新对象作为其响应的一部分,则可以使用它。

如果您需要做的就是将两个或三个现有类型混搭在一起,并且您不想仅为此组合添加类/结构,它还允许您将内置类型用作返回类型。(是否希望函数可以返回匿名类型?这是这种情况的部分答案。)


该死的。真好 我希望几年前已经检查过元组;)。
sabiland



4

就个人而言,当您处于调查周期或只是“玩耍”时,我发现Tuples是开发的迭代部分。因为元组是泛型的,所以在使用泛型参数时,我倾向于考虑使用它-尤其是当要开发泛型代码时,并且我从代码结尾开始,而不是问自己“我希望这个调用如何”看吗?”。

我经常会意识到,元组形成的集合成为列表的一部分,并且盯着List>并没有真正表达出列表的意图或工作方式。我经常“使用”它,但是发现自己想要操纵列表并更改值-此时,我不一定要为此创建一个新的元组,因此我需要创建自己的类或结构来保存它,所以我可以添加操作代码。

当然,总是有扩展方法-但通常您不想将这些额外的代码扩展到通用实现。

有时我想将数据表示为元组,而没有元组可用。(VS2008),在这种情况下,我只是创建了自己的Tuple类-并没有使它成为线程安全的(不可变的)。

因此,我想我认为Tuples是懒惰的编程,但要失去描述其用途的类型名称。另一个开销是,无论用作参数的元组的签名都必须声明。在许多方法开始显得肿之后,您可能会像我一样感觉到,值得创建一个类,因为它可以清理方法签名。

我倾向于从让该类成为您已经在使用的类的公共成员开始。但是当它扩展到不仅仅是一个值的集合的那一刻,它得到的是它自己的文件,然后将其移出包含类。

因此,回想起来,我相信当我不想离开并写一堂课时,我只是想考虑一下我现在在写什么,所以我使用了Tuples。这意味着元组的签名在文本中可能会在半小时内发生很大变化,而我要弄清楚此方法需要什么数据,以及它如何返回将返回的值。

如果我有机会重构代码,那么通常我会质疑元组在其中的位置。


3

自2010年以来一直是现在的问题,现在到2017年,Dotnet发生了变化,变得更加聪明。

C#7引入了对元组的语言支持,它使用新的更有效的元组类型启用元组字段的语义名称。

在vs 2017和.Net 4.7中(或安装nuget包System.ValueTuple),您可以以非常有效和简单的方式创建/使用元组:

     var person = (Id:"123", Name:"john"); //create tuble with two items
     Console.WriteLine($"{person.Id} name:{person.Name}") //access its fields

从一个方法返回多个值:

    public (double sum, double average) ComputeSumAndAverage(List<double> list)
    {
       var sum= list.Sum();
        var average = sum/list.Count;
        return (sum, average);
    }

    How to use:

        var list=new List<double>{1,2,3};
        var result = ComputeSumAndAverage(list);
        Console.WriteLine($"Sum={result.sum} Average={result.average}");    

有关更多详细信息,请阅读:https : //docs.microsoft.com/zh-cn/dotnet/csharp/tuples


1

当您不想创建特定类型时,通常使用元组从函数返回多个值。如果您熟悉Python,Python已经使用了很长时间。


1

从一个函数返回多个值。如果getCoordinates()仅返回x或y或z,则不是很有用,但是使完整的类和对象容纳三个int似乎也很重要。


1

一种常见的用法是避免创建仅包含2个字段的类/结构,而是创建一个Tuple(或现在的KeyValuePair)。有用作为返回值,避免传递N参数。


0

我发现C#中的KeyValuePair刷新以遍历Dictionary中的键值对。


KeyValuePair可以视为特殊用途的解决方法。在Python中,迭代一个Just dict返回(键,值)元组。
dan04 2010年

是的,就像python。:-)我不知道C#中的KeyValuePair不是元组吗?
Jubal

0

从函数返回值时,它确实很有帮助。我们可以返回多个值,这在某些情况下可以节省很多。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.