Как легко инициализировать список кортежей?

Я люблю ОК. Они позволяют быстро сгруппировать релевантную информацию без необходимости писать для нее структуру или класс. Это очень полезно при рефакторинге очень локализованного кода.

инициализация списка из них, однако, кажется немного избыточной.

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

разве нет лучшего способа? Я хотел бы решение по линии словарь инициализатора.

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

не можем ли мы использовать аналогичный синтаксис?

8 ответов


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].Index и tupleList[0].Name

рамки 4.6.2 и ниже

вы должны установить System.ValueTuple из пакета Nuget Менеджер.

база 4.7 и выше

он встроен в рамки. Do не установить System.ValueTuple. На самом деле, удалить его и удалите его из каталога bin.

Примечание: В РЕАЛЬНОЙ ЖИЗНИ Я бы не смог выбрать между коровой, цыплятами или самолетом. Я бы действительно разорвалась.


да! это возможно.

на { } синтаксис инициализатора коллекции работает на любом IEnumerable тип, который имеет добавить метод с правильным количеством аргументов. Не беспокоясь о том, как это работает под одеялом, это означает, что вы можете просто расширить от Список добавить пользовательский метод 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 добавляет новую функцию только для этого: расширение Добавить методы. Это всегда было возможно для VB.net но теперь доступен в C#.

теперь вам не нужно добавлять Add() методы для ваших классов напрямую, вы можете реализовать их как методы расширения. При расширении любого перечисляемого типа с помощью Add() метод, вы сможете использовать его в коллекцию выражение инициализатор. Таким образом, вам больше не нужно явно выводить из списков (как уже упоминалось в другом ответ), вы можете просто продлить его.

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 },
};

конечно, вы не ограничены расширением коллекций кортежей, это может быть для коллекций любого конкретного типа, для которого вы хотите специальный синтаксис.

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 будет добавлять поддержку кортежей, встроенных в язык, хотя они будут другого типа (System.ValueTuple вместо). Так это было бы неплохо добавить перегрузки для кортежей значений, чтобы у вас была возможность их использовать. К сожалению, между ними нет неявных преобразований, определенных между ними.

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 points = new List<(int, int, int)>
{
    (0, 0, 0),
    (1, 2, 3),
    (-1, 12, -73),
};

вы можете сделать это, вызывая конструктор каждый раз с немного лучше

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

почему бы кортежи? Это как анонимные типы: без имен. Не могу понять структуру данных.

Мне нравятся классические классы

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

    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>