如何轻松初始化元组列表?

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

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

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

没有更好的方法吗? 我会喜欢字典初始值设定项的解决scheme。

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

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

是! 这是可能的 。

集合初始值设定项的{}语法适用于具有正确数量参数的Add方法的任何IEnumerabletypes。 不用担心如何在封面下工作,这意味着你可以简单地从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" } }; 

C#6为此添加了一个新function:扩展添加方法。 对于VB.net来说,这一直是可能的,但现在可以在C#中使用。

现在,您不必直接将Add()方法Add()到类中,就可以将它们实现为扩展方法。 使用Add()方法扩展任何枚举types时,您将能够在集合初始值设定项expression式中使用它。 所以你不必从列表中明确地派生出来( 正如在另一个答案中提到的那样 ),你可以简单地扩展它。

 public static class TupleListExtensions { public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list, T1 item1, T2 item2) { list.Add(Tuple.Create(item1, item2)); } public static void Add<T1, T2, T3>(this IList<Tuple<T1, T2, T3>> list, T1 item1, T2 item2, T3 item3) { list.Add(Tuple.Create(item1, item2, item3)); } // and so on... } 

这将允许您在任何实现IList<>类上执行此操作:

 var numbers = new List<Tuple<int, string>> { { 1, "one" }, { 2, "two" }, { 3, "three" }, { 4, "four" }, { 5, "five" }, }; var points = new ObservableCollection<Tuple<double, double, double>> { { 0, 0, 0 }, { 1, 2, 3 }, { -4, -2, 42 }, }; 

当然,你不限于扩展元组的集合,它可以是任何你想要特殊语法的特定types的集合。

 public static class BigIntegerListExtensions { public static void Add(this IList<BigInteger> list, params byte[] value) { list.Add(new BigInteger(value)); } public static void Add(this IList<BigInteger> list, string value) { list.Add(BigInteger.Parse(value)); } } var bigNumbers = new List<BigInteger> { new BigInteger(1), // constructor BigInteger(int) 2222222222L, // implicit operator BigInteger(long) 3333333333UL, // implicit operator BigInteger(ulong) { 4, 4, 4, 4, 4, 4, 4, 4 }, // extension Add(byte[]) "55555555555555555555555555555555555555", // extension Add(string) }; 

C#7将添加支持构build到语言中的元组,尽pipe它们将是不同的types(而不是System.ValueTuple )。 因此,为值元组添加重载将会很好,所以您可以select使用它们。 不幸的是,两者之间没有定义隐式转换。

 public static class ValueTupleListExtensions { public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list, ValueTuple<T1, T2> item) => list.Add(item.ToTuple()); } 

这样,列表初始化看起来更好。

 var points = new List<Tuple<int, int, int>> { (0, 0, 0), (1, 2, 3), (-1, 12, -73), }; 

但是,不要经历所有这些麻烦,只能切换到专门使用ValueTuple

你可以通过调用构造函数来做到这一点,稍微好一些

 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" ) }; 

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

 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" ) }; 

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].IndextupleList[0].Name

框架4.6.2及以下

您必须从Nuget Package Manager安装System.ValueTuple

框架4.7及以上

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

为什么喜欢元组? 这就像匿名types:没有名字。 不能理解数据的结构。

我喜欢经典课程

 class FoodItem { public int Position { get; set; } public string Name { get; set; } } List<FoodItem> list = new List<FoodItem> { new FoodItem { Position = 1, Name = "apple" }, new FoodItem { Position = 2, Name = "kiwi" } }; 
  var colors = new[] { new { value = Color.White, name = "White" }, new { value = Color.Silver, name = "Silver" }, new { value = Color.Gray, name = "Gray" }, new { value = Color.Black, name = "Black" }, new { value = Color.Red, name = "Red" }, new { value = Color.Maroon, name = "Maroon" }, new { value = Color.Yellow, name = "Yellow" }, new { value = Color.Olive, name = "Olive" }, new { value = Color.Lime, name = "Lime" }, new { value = Color.Green, name = "Green" }, new { value = Color.Aqua, name = "Aqua" }, new { value = Color.Teal, name = "Teal" }, new { value = Color.Blue, name = "Blue" }, new { value = Color.Navy, name = "Navy" }, new { value = Color.Pink, name = "Pink" }, new { value = Color.Fuchsia, name = "Fuchsia" }, new { value = Color.Purple, name = "Purple" } }; foreach (var color in colors) { stackLayout.Children.Add( new Label { Text = color.name, TextColor = color.value, }); FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)) } this is a Tuple<Color, string>