69

.Net 3.5 不支持元组。太糟糕了,但不确定.net 的未来版本是否支持元组?

4

12 回答 12

73

我刚刚阅读了 MSDN 杂志上的这篇文章:Building Tuple

以下是节选:

即将发布的 Microsoft .NET Framework 4.0 版引入了一种称为 System.Tuple 的新类型。System.Tuple 是一个固定大小的异构类型数据集合。    

 

像数组一样,元组具有固定的大小,一旦创建就无法更改。与数组不同,元组中的每个元素可能是不同的类型,并且元组能够保证每个元素的强类型。

 

在 System.Collections.Generic 命名空间中已经有一个在 Microsoft .NET Framework 中浮动的元组示例:KeyValuePair。虽然 KeyValuePair 可以被认为与 Tuple 相同,因为它们都是包含两个东西的类型,但 KeyValuePair 感觉与 Tuple 不同,因为它唤起了它存储的两个值之间的关系(并且有充分的理由,因为它支持 Dictionary 类)。

此外,元组可以任意大小,而 KeyValuePair 只包含两个东西:一个键和一个值。


虽然 F# 等某些语言对元组有特殊语法,但您可以使用任何语言的新通用元组类型。回顾第一个例子,我们可以看到虽然有用,但元组在没有元组语法的语言中可能过于冗长:

class Program {
    static void Main(string[] args) {
        Tuple<string, int> t = new Tuple<string, int>("Hello", 4);
        PrintStringAndInt(t.Item1, t.Item2);
    }
    static void PrintStringAndInt(string s, int i) {
        Console.WriteLine("{0} {1}", s, i);
    }
}

使用 C# 3.0 中的 var 关键字,我们可以删除元组变量上的类型签名,从而使代码更具可读性。

var t = new Tuple<string, int>("Hello", 4);

我们还向静态 Tuple 类添加了一些工厂方法,这使得使用支持类型推断的语言(如 C#)更容易构建元组。

var t = Tuple.Create("Hello", 4);
于 2009-06-26T08:24:10.943 回答
69
#region tuples

    public class Tuple<T>
    {
        public Tuple(T first)
        {
            First = first;
        }

        public T First { get; set; }
    }

    public class Tuple<T, T2> : Tuple<T>
    {
        public Tuple(T first, T2 second)
            : base(first)
        {
            Second = second;
        }

        public T2 Second { get; set; }
    }

    public class Tuple<T, T2, T3> : Tuple<T, T2>
    {
        public Tuple(T first, T2 second, T3 third)
            : base(first, second)
        {
            Third = third;
        }

        public T3 Third { get; set; }
    }

    public class Tuple<T, T2, T3, T4> : Tuple<T, T2, T3>
    {
        public Tuple(T first, T2 second, T3 third, T4 fourth)
            : base(first, second, third)
        {
            Fourth = fourth;
        }

        public T4 Fourth { get; set; }
    }

    #endregion

并使声明更漂亮:

public static class Tuple
{
    //Allows Tuple.New(1, "2") instead of new Tuple<int, string>(1, "2")
    public static Tuple<T1, T2> New<T1, T2>(T1 t1, T2 t2)
    {
        return new Tuple<T1, T2>(t1, t2);
    }
    //etc...
}
于 2008-09-30T07:02:43.020 回答
15

Lokad 共享库(当然是开源的)中有一个适当的(不快速的)C# Tuple实现,其中包括以下必需的特性:

  • 2-5 不可变元组实现
  • 正确的 DebuggerDisplayAttribute
  • 正确的散列和相等检查
  • 用于从提供的参数生成元组的助手(泛型由编译器推断)和基于集合的操作的扩展。
  • 生产测试。
于 2009-01-09T16:11:59.330 回答
14

在 C# 中实现元组类或重用 F# 类只是故事的一半——这些使您能够相对轻松地创建元组,但并不是真正的语法糖,使它们在 F# 等语言中使用起来非常好。

例如,在 F# 中,您可以使用模式匹配在 let 语句中提取元组的两个部分,例如

let (a, b) = someTupleFunc

不幸的是,使用 C# 中的 F# 类做同样的事情会不太优雅:

Tuple<int,int> x = someTupleFunc();
int a = x.get_Item1();
int b = x.get_Item2();

元组代表了一种强大的方法,可以从函数调用中返回多个值,而无需在代码中乱扔垃圾类,或者使用丑陋的 ref 或 out 参数。然而,在我看来,如果没有一些语法糖来使它们的创建和访问更加优雅,它们的用途是有限的。

于 2008-09-30T12:21:36.387 回答
12

在我看来,匿名类型特性不是一个元组,而是一个非常相似的构造。一些 LINQ 查询的输出是匿名类型的集合,其行为类似于元组。

这是一个语句,它动态创建一个类型化的元组:-):

var p1 = new {a = "A", b = 3};

见: http: //www.developer.com/net/csharp/article.php/3589916

于 2008-09-30T07:13:30.233 回答
5

C# 7 原生支持元组:

var unnamedTuple = ("Peter", 29);
var namedTuple = (Name: "Peter", Age: 29);
(string Name, double Age) typedTuple = ("Peter", 29);
于 2017-03-07T10:53:15.407 回答
3

C# 很容易通过泛型支持简单的元组(根据较早的答案),并且通过“mumble typing”(许多可能的 C# 语言增强之一)来改进类型推断,它们可能非常非常强大。

就其价值而言,F# 本身就支持元组,并且在使用它之后,我不确定(匿名)元组会增加多少......你在简洁中获得的东西在代码清晰度方面会很快失去。

对于单个方法中的代码,有匿名类型;对于方法之外的代码,我想我会坚持使用简单的命名类型。当然,如果未来的 C# 可以更容易地使这些不可变(同时仍然易于使用),我会很高兴。

于 2008-09-30T07:28:17.000 回答
3

我的开源 .NET Sasa 库多年来一直拥有元组(以及许多其他功能,例如完整的 MIME 解析)。几年来,我一直在生产代码中使用它。

于 2009-12-01T04:32:09.207 回答
2

这是我的一组元组,它们是由 Python 脚本自动生成的,所以我可能有点过火了:

链接到 Subversion 存储库

你需要一个用户名/密码,他们都是客人

它们基于继承,但Tuple<Int32,String>不会比较等于,Tuple<Int32,String,Boolean>即使它们碰巧对前两个成员具有相同的值。

他们还实现了 GetHashCode 和 ToString 等,以及许多小的辅助方法。

使用示例:

Tuple<Int32, String> t1 = new Tuple<Int32, String>(10, "a");
Tuple<Int32, String, Boolean> t2 = new Tuple<Int32, String, Boolean>(10, "a", true);
if (t1.Equals(t2))
    Console.Out.WriteLine(t1 + " == " + t2);
else
    Console.Out.WriteLine(t1 + " != " + t2);

将输出:

10, a != 10, a, True
于 2009-01-06T17:33:18.660 回答
1

如果我没记错我的计算机科学课,元组只是数据。

如果您想要分组数据 - 创建包含属性的类。如果您需要类似KeyValuePair的东西,那么它就在那里。

于 2008-09-30T07:03:13.877 回答
0

我会感到惊讶 - C# 是一种强类型语言,而元组适用于更动态类型的语言。随着时间的推移,C# 变得更加动态,但这是语法糖,而不是底层数据类型的真正转变。

如果您想在一个实例中使用两个值,则 KeyValuePair<> 是一个不错的替代品,尽管很笨拙。您还可以创建一个结构或类来做同样的事情,并且是可扩展的。

于 2008-09-30T07:07:59.077 回答
0

为了使这些在哈希表或字典中有用,您可能希望为 GetHashCode 和 Equals 提供重载。

于 2009-01-06T17:23:37.963 回答