web-dev-qa-db-fra.com

Existe-t-il une astuce pour créer une liste générique de type anonyme?

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 

36
OopsUser

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);
92
alex

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);
17
HackedByChinese

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

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;
6
Puchacz

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}
);
5
Sean

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);
2
Dmytro

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.

1

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) });
1
rrreee

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});
0
Elion Limanaj