我喜欢元组。它们允许您快速地将相关信息分组在一起,而不必为此编写结构或类。这在重构非常本地化的代码时非常有用。

然而,初始化它们的列表似乎有点多余。

var tupleList = new List<Tuple<int, string>>
{
    Tuple.Create( 1, "cow" ),
    Tuple.Create( 5, "chickens" ),
    Tuple.Create( 1, "airplane" )
};

难道没有更好的办法吗?我希望有一个类似Dictionary初始化式的解决方案。

Dictionary<int, string> students = new Dictionary<int, string>()
{
    { 111, "bleh" },
    { 112, "bloeh" },
    { 113, "blah" }
};

我们不能使用类似的语法吗?


当前回答

您可以通过每次调用构造函数来实现这一点

var tupleList = new List<Tuple<int, string>>
{
    new Tuple<int, string>(1, "cow" ),
    new Tuple<int, string>( 5, "chickens" ),
    new Tuple<int, string>( 1, "airplane" )
};

其他回答

超级老我知道,但我会在使用Linq和使用c# 7的方法上添加我的部分。在类中重用时,我尝试使用命名元组替换dto和匿名投影。是的,对于模拟和测试,你仍然需要类,但是内联做事情和在类中传递是很好的,有这个更新的选项。您可以实例化它们

直接实例化

var items = new List<(int Id, string Name)> { (1, "Me"), (2, "You")};

现在您可以返回类型良好的元组,类似于匿名投影的方式。

public class Hold
{
    public int Id { get; set; }
    public string Name { get; set; }
}

//In some method or main console app:
var holds = new List<Hold> { new Hold { Id = 1, Name = "Me" }, new Hold { Id = 2, Name = "You" } };
var anonymousProjections = holds.Select(x => new { SomeNewId = x.Id, SomeNewName = x.Name });
var namedTuples = holds.Select(x => (TupleId: x.Id, TupleName: x.Name));

稍后使用分组方法重用这些元组,或者使用其他逻辑中的方法内联构造它们:

//Assuming holder class above making 'holds' object
public (int Id, string Name) ReturnNamedTuple(int id, string name) => (id, name);
public static List<(int Id, string Name)> ReturnNamedTuplesFromHolder(List<Hold> holds) => holds.Select(x => (x.Id, x.Name)).ToList();
public static void DoSomethingWithNamedTuplesInput(List<(int id, string name)> inputs) => inputs.ForEach(x => Console.WriteLine($"Doing work with {x.id} for {x.name}"));

var namedTuples2 = holds.Select(x => ReturnNamedTuple(x.Id, x.Name));
var namedTuples3 = ReturnNamedTuplesFromHolder(holds);
DoSomethingWithNamedTuplesInput(namedTuples.ToList());

我认为有一个技巧比较简单,但之前没有提到过:

var asdf = new [] { 
    (Age: 1, Name: "cow"), 
    (Age: 2, Name: "bird")
}.ToList();

我认为这比:

var asdf = new List<Tuple<int, string>> { 
    (Age: 1, Name: "cow"), 
    (Age: 2, Name: "bird")
};

c# 7.0允许你这样做:

  var tupleList = new List<(int, string)>
  {
      (1, "cow"),
      (5, "chickens"),
      (1, "airplane")
  };

如果你不需要List,而只是一个数组,你可以这样做:

  var tupleList = new(int, string)[]
  {
      (1, "cow"),
      (5, "chickens"),
      (1, "airplane")
  };

如果你不喜欢“Item1”和“Item2”,你可以做:

  var tupleList = new List<(int Index, string Name)>
  {
      (1, "cow"),
      (5, "chickens"),
      (1, "airplane")
  };

或者对于数组:

  var tupleList = new (int Index, string Name)[]
  {
      (1, "cow"),
      (5, "chickens"),
      (1, "airplane")
  };

tupleList[0]。索引和tupleList[0]。的名字

框架4.6.2及以下

您必须安装系统。Nuget包管理器中的ValueTuple。

框架4.7及以上

它被内置到框架中。不要安装System.ValueTuple。实际上,将其从bin目录中删除。

注意:在现实生活中,我无法在牛、鸡和飞机之间做出选择。我真的会很纠结。

老问题了,但这是我通常做的事情,让事情更具可读性:

Func<int, string, Tuple<int, string>> tc = Tuple.Create;

var tupleList = new List<Tuple<int, string>>
{
    tc( 1, "cow" ),
    tc( 5, "chickens" ),
    tc( 1, "airplane" )
};

是的!这是可能的。

集合初始化式的{}语法适用于任何IEnumerable 类型,它有一个添加方法,参数数量正确。 不用担心在被窝里是怎么工作的,这意味着你可以 简单地从List<T>扩展,添加一个自定义的add方法来初始化您的 T,你完成了!

public class TupleList<T1, T2> : List<Tuple<T1, T2>>
{
    public void Add( T1 item, T2 item2 )
    {
        Add( new Tuple<T1, T2>( item, item2 ) );
    }
}

这允许你做以下事情:

var groceryList = new TupleList<int, string>
{
    { 1, "kiwi" },
    { 5, "apples" },
    { 3, "potatoes" },
    { 1, "tomato" }
};