Tuple.Create()与new Tuple的区别

54

考虑以下表达式:

new Tuple<int,int>(1,2);

Tuple.Create(1,2);

这两种元组创建方法有什么区别吗?根据我的阅读,它似乎更像是一种便捷的简写,而不像C++中的对象创建(堆 vs 栈)。


3
var 关键字的存在是因为 Tuple<int, int> t1 = new Tuple<int,int>(1,2); 这样的语句过于冗长,使用 var 可以让代码更简洁易读。注意不要改变原来的意思。 - Federico Berasategui
5个回答

33

就个人而言,我觉得Tuple.Create()不那么啰嗦,更易于阅读。

实际上,在底层没有区别。 Tuple.Create()的重载方法只是一堆调用你发布的第一个版本的静态方法:

public static class Tuple
{
    public static Tuple<T1> Create<T1>(T1 item1) {
        return new Tuple<T1>(item1);
    }

    public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2) {
        return new Tuple<T1, T2>(item1, item2);
    }

    public static Tuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3) {
        return new Tuple<T1, T2, T3>(item1, item2, item3);
    }

    ...

我想其中一个好处是,由于您不必使用Tuple.Create指定类型,因此您可以存储匿名类型,否则您无法确定其类型。

public class Person
{
    public string Name { get; set; }
    public int Height { get; set; }
    public DateTime BirthDate { get; set; }
}

var people = new List<Person>
{
    new Person { Name = "Bob", Height = 72, BirthDate = new DateTime(1984,1,1) },
    new Person { Name = "Mary", Height = 64, BirthDate = new DateTime(1980,2,2) }
};

var oneAnonList = people.Select(x => new { x.Name, x.BirthDate });
var twoAnonList = people.Select(x => new { x.Height, x.Name });

var myTuple = Tuple.Create(oneAnonList, twoAnonList);

这将创建一个包含两个匿名类型的元组,第一个是new { string Name, DateTime BirthDate },第二个是new { int Height, string Name }

由于要传递到另一个方法中,仍然需要能够定义参数的“类型”,因此您可以做的仍然不是太多。所以它真的取决于方便性。


但对我来说,它让我想起了建造者模式,由于它没有使用该模式,我更喜欢使用new关键字。 - John Demetriou

23

Tuple.Create 的好处在于通常可以省略类型参数,例如 Tuple.Create(1,2)new Tuple<int,int>(1,2) 更简洁。

如果你尝试从构造函数 new Tuple(1,2) 中省略类型参数,你会看到错误 CS0712 "无法创建静态类 'Tuple' 的实例""


不是所有的情况都成立。你可以看到我的答案。祝好! - taquion

15

这个问题看起来有点旧了,但我认为我仍然可以做出有建设性的贡献。从被接受的答案中可以得知:

我想其中一个好处是,由于您无需使用 Tuple.Create 指定类型,因此可以存储匿名类型,否则您将无法确定其类型。

后面那一句话是正确的:您可以存储匿名类型,而您无法确定这些类型是什么。

但是第一部分:

由于您无需使用 Tuple.Create 指定类型

并不总是正确的。考虑以下情况:

interface IAnimal
{
}

class Dog : IAnimal
{
}
以下代码将无法编译:
Tuple<IAnimal> myWeirdTuple;

myWeirdTuple = Tuple.Create(new Dog());

您将需要在创建方法中指定类型参数,如下所示:

myWeirdTuple = Tuple.Create<IAnimal>(new Dog());

在我看来,这段代码 new Tuple<IAnimal>(new Dog()) 就像一个过于冗长的调用。


1
没错,你只需要重写括号内的单词... 到目前为止字符数量相同... <IAnimal> 和 (IAnimal)。 - taquion
1
不要误会,我同意你的答案。由于C#在构造函数中没有泛型类型推断,因此创建了Tuple.Create,但它仍然不总是有效。在您的反例中,您不再传递Dog类型,而是IAnimal类型。这是因为,嗯,C#不允许协变类。 - taquion
只是为了记录而言,由于Tuple是不可变的,所以协变类在这里是可以的。 - taquion

12

从 C# 7 开始,你现在可以像这样简单地声明 Value Tuple:

Starting with C# 7, 你现在可以像这样简单地声明 Value Tuple:

var unnamed = (1, 2);
或者
var named = (name: "Joe", age: 2);

请参阅 Microsoft 文档:https://learn.microsoft.com/zh-cn/dotnet/csharp/tuples


8

4
不再需要链接第三方网站了,微软创建了一个参考源的网络界面。[http://referencesource.microsoft.com/#mscorlib/system/tuple.cs,9124c4bea9ab0199] - Scott Chamberlain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接