Parfois, j'ai besoin d'utiliser un tuple, par exemple j'ai une liste de chars et de leurs chars cibles (ils les pourchassent ou quelque chose comme ça):
List<Tuple<Tank,Tank>> mylist = new List<Tuple<Tank,Tank>>();
et puis quand j'itère sur la liste je les accède par
mylist[i].item1 ...
mylist[i].item2 ...
C'est très déroutant et j'oublie toujours ce que sont item1 et item2, si je pouvais y accéder par:
mylist[i].AttackingTank...
mylist[i].TargetTank...
Ce serait beaucoup plus clair, y a-t-il un moyen de le faire sans définir de classe:
MyTuple
{
public Tank AttackingTank;
public Tank TargetTank;
}
Je veux éviter de définir cette classe, car je devrais alors définir de nombreuses classes différentes dans différents scénarios. Puis-je faire quelques "astuces" et rendre cela anonyme?.
Quelque chose comme :
var k = new {Name = "me", phone = 123};
mylist.Add(k);
Le problème bien sûr que je n'ai pas de type à passer à la liste quand je le définis
Vous pouvez créer une liste vide pour les types anonymes, puis l'utiliser, en bénéficiant de contrôles intellisense complets et au moment de la compilation:
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);
Vous pouvez utiliser un List<dynamic>
.
var myList = new List<dynamic>();
myList.Add(new {Tank = new Tank(), AttackingTank = new Tank()});
Console.WriteLine("AttackingTank: {0}", myList[0].AttackingTank);
Voici un hack:
var myList = Enumerable.Empty<int>()
.Select(dummy => new { AttackingTank = default(Tank), TargetTank = default(Tank), })
.ToList();
Si Tank
est un type de classe, vous pouvez écrire (Tank)null
au lieu de default(Tank)
. Vous pouvez également utiliser une instance Tank
que vous avez sous la main.
MODIFIER:
Ou:
var myList = Enumerable.Repeat(
new { AttackingTank = default(Tank), TargetTank = default(Tank), },
0).ToList();
Si vous créez une méthode générique, vous n’aurez pas à utiliser Enumerable.Empty
. Ça pourrait aller comme ça:
static List<TAnon> GetEmptyListWithAnonType<TAnon>(TAnon dummyParameter)
{
return new List<TAnon>();
}
Il doit être appelé avec le TAnon
déduit de l'usage, bien sûr, comme dans:
var myList = GetEmptyListWithAnonType(new { AttackingTank = default(Tank), TargetTank = default(Tank), });
Il est intéressant de noter que finalement, il est possible d'utiliser une telle syntaxe. Il avait été introduit en C # 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;
Vous pouvez simplement avoir une méthode générique qui prend une params
et la renvoie:
public static IList<T> ToAnonymousList<T>(params T[] items)
{
return items;
}
Alors maintenant, vous pouvez dire:
var list=ToAnonymousList
(
new{A=1, B=2},
new{A=2, B=2}
);
Que diriez-vous de ExpandoObject ?
dynamic Tuple = new ExpandoObject();
Tuple.WhatEverYouWantTypeOfTank = new Tank(); // Value of any type
EDITS:
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);
Ou même plus simple
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();
Qui perd la fonction statique.
Juste pour ajouter un peu plus pratique ici. J'utilise parfois la réponse d'Alex, mais cela me rend un peu fou d'essayer de la retrouver quand j'en ai besoin, car ce n'est pas évident (je me trouve à la recherche de "nouveau {").
J'ai donc ajouté la petite méthode statique suivante (j'aimerais pouvoir en faire une méthode d'extension, mais de quel type?):
public static List<T> CreateEmptyListOf<T>(Func<T> itemCreator)
{
return Enumerable
.Empty<object>()
.Select(o => itemCreator())
.ToList();
}
Cela isole la partie qui est différente chaque fois que j'ai besoin de ce motif de celles qui sont identiques. Je l'appelle comme ça:
var emptyList = Ext.CreateEmptyListOf(() => new { Name = default(string), SomeInt = default(int) });
Vous pouvez créer une liste d'objets:
List<object> myList = new List<object>();
Ajoutez ensuite le type anonyme à votre liste:
myList.Add(new {Name = "me", phone = 123});