Есть ли трюк в создании общего списка анонимного типа?
Иногда мне нужно использовать Tuple, например, у меня есть список танков и их целевых танков (они преследуют их или что-то в этом роде):
List<Tuple<Tank,Tank>> mylist = new List<Tuple<Tank,Tank>>();
а затем, когда я перебираю список, я обращаюсь к ним через
mylist[i].item1 ...
mylist[i].item2 ...
Это очень запутанно, и я всегда забываю, что такое item1 и что item2, если бы я мог получить к ним доступ:
mylist[i].AttackingTank...
mylist[i].TargetTank...
Было бы намного понятнее, есть ли способ сделать это, не определяя класс:
MyTuple
{
public Tank AttackingTank;
public Tank TargetTank;
}
Я хочу избежать определения этого класса, потому что тогда мне придется определять много разных классов в разных сценариях, могу ли я сделать "трюк" и сделать это анонимным.
Что-то вроде:
var k = new {Name = "me", phone = 123};
mylist.Add(k);
Проблема, конечно, что у меня нет типа для перехода к списку, когда я его определяю
Ответы
Ответ 1
Вы можете создать пустой список для анонимных типов, а затем использовать его, используя полную проверку интеллекта и времени компиляции:
var list = Enumerable.Empty<object>()
.Select(r => new {A = 0, B = 0}) // prototype of anonymous type
.ToList();
list.Add(new { A = 4, B = 5 }); // adding actual values
Console.Write(list[0].A);
Ответ 2
Вы можете использовать List<dynamic>
.
var myList = new List<dynamic>();
myList.Add(new {Tank = new Tank(), AttackingTank = new Tank()});
Console.WriteLine("AttackingTank: {0}", myList[0].AttackingTank);
Ответ 3
Вот хак:
var myList = Enumerable.Empty<int>()
.Select(dummy => new { AttackingTank = default(Tank), TargetTank = default(Tank), })
.ToList();
Если Tank
- тип класса, вы можете написать (Tank)null
вместо default(Tank)
. Вы также можете использовать экземпляр Tank
, который у вас есть.
EDIT:
Или:
var myList = Enumerable.Repeat(
new { AttackingTank = default(Tank), TargetTank = default(Tank), },
0).ToList();
Если вы создадите общий метод, вам не придется использовать Enumerable.Empty
. Это может выглядеть так:
static List<TAnon> GetEmptyListWithAnonType<TAnon>(TAnon dummyParameter)
{
return new List<TAnon>();
}
Он должен быть вызван с TAnon
, который выведен из использования, конечно, как в:
var myList = GetEmptyListWithAnonType(new { AttackingTank = default(Tank), TargetTank = default(Tank), });
Ответ 4
У вас может быть только общий метод, который принимает params
и возвращает его:
public static IList<T> ToAnonymousList<T>(params T[] items)
{
return items;
}
Итак, теперь вы можете сказать:
var list=ToAnonymousList
(
new{A=1, B=2},
new{A=2, B=2}
);
Ответ 5
Стоит отметить, что, наконец, есть возможность использовать такой синтаксис. Он был введен в С# 7.0
var tanks = new List<(Tank AttackingTank, Tank TargetTank)>();
(Tank, Tank) tTank = (new Tank(), new Tank());
tanks.Add(tTank);
var a = tanks[0].AttackingTank;
var b = tanks[0].TargetTank;
Ответ 6
Как насчет ExpandoObject?
dynamic tuple = new ExpandoObject();
tuple.WhatEverYouWantTypeOfTank = new Tank(); // Value of any type
редактирует:
dynamic tuple = new ExpandoObject();
tuple.AttackingTank = new Tank();
tuple.TargetTank = new Tank();
var mylist = new List<dynamic> { tuple };
//access to items
Console.WriteLine(mylist[0].AttackingTank);
Ответ 7
Или даже более простой
var tupleList = (
new[] {
new { fruit = "Tomato", colour = "red"},
new { fruit = "Tomato", colour = "yellow"},
new { fruit = "Apple", colour = "red"},
new { fruit = "Apple", colour = "green"},
new { fruit = "Medlar", colour = "russet"}
}).ToList();
Которая теряет статическую функцию.
Ответ 8
Просто добавьте еще один удобный бит. Иногда я использую ответ Алекс, но он немного меня раздражает, пытаясь отследить его, когда он мне нужен, так как он не очевиден (я нахожусь в поиске "нового {" ).
Итак, я добавил следующий небольшой статический метод (хотел бы я сделать его методом расширения, но какого типа?):
public static List<T> CreateEmptyListOf<T>(Func<T> itemCreator)
{
return Enumerable
.Empty<object>()
.Select(o => itemCreator())
.ToList();
}
Это изолирует часть, которая отличается каждый раз, когда мне нужен этот шаблон из тех, которые являются одинаковыми. Я называю это следующим образом:
var emptyList = Ext.CreateEmptyListOf(() => new { Name = default(string), SomeInt = default(int) });