Aujourd'hui, j'ai été surpris de constater qu'en C # je peux faire:
List<int> a = new List<int> { 1, 2, 3 };
Pourquoi puis-je faire ça? Quel constructeur s'appelle? Comment puis-je faire cela avec mes propres cours? Je sais que c'est la manière d'initialiser les tableaux, mais les tableaux sont des éléments de langage et les listes sont des objets simples ...
c#
.net
list
initialization
Ignacio Soler Garcia
la source
la source
{ { "key1", "value1"}, { "key2", "value2"} }
List<int>
est en fait un tableau uniquement. Je déteste l'équipe C # pour le fait qu'ils ne la nomment pas, ceArrayList<T>
qui semble si évident et naturel.Réponses:
Cela fait partie de la syntaxe d'initialisation de collection dans .NET. Vous pouvez utiliser cette syntaxe sur n'importe quelle collection que vous créez tant que:
Il met en œuvre
IEnumerable
(de préférenceIEnumerable<T>
)Il a une méthode nommée
Add(...)
Ce qui se passe, c'est que le constructeur par défaut est appelé, puis
Add(...)
est appelé pour chaque membre de l'initialiseur.Ainsi, ces deux blocs sont à peu près identiques:
Et
Vous pouvez appeler un constructeur alternatif si vous le souhaitez, par exemple pour éviter de surdimensionner le
List<T>
pendant la croissance, etc.:Notez que la
Add()
méthode n'a pas besoin de prendre un seul élément, par exemple laAdd()
méthode pourDictionary<TKey, TValue>
prend deux éléments:Est à peu près identique à:
Donc, pour ajouter ceci à votre propre classe, tout ce que vous avez à faire, comme mentionné, est d'implémenter
IEnumerable
(encore une fois, de préférenceIEnumerable<T>
) et de créer une ou plusieursAdd()
méthodes:Ensuite, vous pouvez l'utiliser comme le font les collections BCL:
(Pour plus d'informations, consultez le MSDN )
la source
List<int> temp = new List<int>(); temp.Add(1); ... List<int> a = temp;
Autrement dit, laa
variable n'est initialisée qu'après l'appel de tous les ajouts. Sinon, il serait légal de faire quelque chose commeList<int> a = new List<int>() { a.Count, a.Count, a.Count };
ce qui est fou.List<int> a; a = new List<int>() { a.Count };
etList<int> a = new List<int>() { a.Count };
T x = y;
c'est la même chose queT x; x = y;
, Ce fait peut conduire à des situations étranges. Par exemple,int x = M(out x) + x;
c'est parfaitement légal parce queint x; x = M(out x) + x;
c'est légal.IEnumerable<T>
; le non-génériqueIEnumerable
suffit pour permettre l'utilisation de la syntaxe d'initialisation de collection.using (var x = new Something{ 1, 2 })
ne supprimera pas l'objet si l'un desAdd
appels échoue.C'est ce qu'on appelle le sucre syntaxique .
List<T>
est la classe "simple", mais le compilateur lui donne un traitement spécial afin de vous faciliter la vie.Celui-ci est appelé initialiseur de collection . Vous devez mettre en œuvre
IEnumerable<T>
etAdd
méthode.la source
Selon la spécification C # version 3.0 "L'objet de collection auquel un initialiseur de collection est appliqué doit être d'un type qui implémente System.Collections.Generic.ICollection pour exactement un T."
Cependant, ces informations semblent inexactes au moment de la rédaction de cet article; voir la clarification d'Eric Lippert dans les commentaires ci-dessous.
la source
Cela fonctionne grâce aux initialiseurs de collection qui nécessitent essentiellement que la collection implémente une méthode Add et qui fera le travail pour vous.
la source
Une autre chose intéressante à propos des initialiseurs de collection est que vous pouvez avoir plusieurs surcharges de
Add
méthode et vous pouvez les appeler toutes dans le même initialiseur! Par exemple, cela fonctionne:Il appelle les surcharges correctes. En outre, il ne recherche que la méthode avec le nom
Add
, le type de retour peut être n'importe quoi.la source
Le tableau comme la syntaxe est tourné dans une série d'
Add()
appels.Pour voir cela dans un exemple beaucoup plus intéressant, considérons le code suivant dans lequel je fais deux choses intéressantes qui semblent d'abord illégales en C #, 1) définir une propriété en lecture seule, 2) définir une liste avec un tableau comme initializer.
Ce code fonctionnera parfaitement, même si 1) MyList est en lecture seule et 2) j'ai défini une liste avec un initialiseur de tableau.
La raison pour laquelle cela fonctionne, c'est que dans le code qui fait partie d'un initiateur d'objet, le compilateur transforme toujours une
{}
syntaxe similaire en une série d'Add()
appels qui sont parfaitement légaux même sur un champ en lecture seule.la source