web-dev-qa-db-fra.com

Pourquoi puis-je initialiser une liste comme un tableau en C #?

Aujourd'hui, j'ai été surpris de constater qu'en C # je peux faire:

List<int> a = new List<int> { 1, 2, 3 };

Pourquoi est-ce que je peux faire ça? Quel constructeur s'appelle? Comment puis-je faire cela avec mes propres cours? Je sais que c'est la façon d'initialiser les tableaux, mais les tableaux sont des éléments de langage et les listes sont des objets simples ...

131

Cela fait partie de la syntaxe d'initialisation de la collection dans .NET. Vous pouvez utiliser cette syntaxe sur n'importe quelle collection que vous créez tant que:

  • Il implémente IEnumerable (de préférence IEnumerable<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:

List<int> a = new List<int> { 1, 2, 3 };

Et

List<int> temp = new List<int>();
temp.Add(1);
temp.Add(2);
temp.Add(3);
List<int> a = temp;

Vous pouvez appeler un constructeur alternatif si vous le souhaitez, par exemple pour éviter de surdimensionner le List<T> Pendant la croissance, etc:

// Notice, calls the List constructor that takes an int arg
// for initial capacity, then Add()'s three items.
List<int> a = new List<int>(3) { 1, 2, 3, }

Notez que la méthode Add() n'a pas besoin de prendre un seul élément, par exemple la méthode Add() pour Dictionary<TKey, TValue> Prend deux éléments:

var grades = new Dictionary<string, int>
    {
        { "Suzy", 100 },
        { "David", 98 },
        { "Karen", 73 }
    };

Est à peu près identique à:

var temp = new Dictionary<string, int>();
temp.Add("Suzy", 100);
temp.Add("David", 98);
temp.Add("Karen", 73);
var grades = temp;

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érence IEnumerable<T>) Et de créer une ou plusieurs méthodes Add() :

public class SomeCollection<T> : IEnumerable<T>
{
    // implement Add() methods appropriate for your collection
    public void Add(T item)
    {
        // your add logic    
    }

    // implement your enumerators for IEnumerable<T> (and IEnumerable)
    public IEnumerator<T> GetEnumerator()
    {
        // your implementation
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Ensuite, vous pouvez l'utiliser comme le font les collections BCL:

public class MyProgram
{
    private SomeCollection<int> _myCollection = new SomeCollection<int> { 13, 5, 7 };    

    // ...
}

(Pour plus d'informations, consultez le MSDN )

183
James Michael Hare

C'est ce qu'on appelle 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 implémenter IEnumerable<T> et Add, méthode.

11
Krizz

Selon la spécification C # version 3. "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.

8

Une autre chose intéressante à propos des initialiseurs de collection est que vous pouvez avoir plusieurs surcharges de la méthode Add et vous pouvez les appeler toutes dans le même initialiseur! Par exemple, cela fonctionne:

public class MyCollection<T> : IEnumerable<T>
{
    public void Add(T item, int number)
    {

    }
    public void Add(T item, string text) 
    {

    }
    public bool Add(T item) //return type could be anything
    {

    }
}

var myCollection = new MyCollection<bool> 
{
    true,
    { false, 0 },
    { true, "" },
    false
};

Il appelle les surcharges correctes. En outre, il recherche uniquement la méthode avec le nom Add, le type de retour peut être n'importe quoi.

6
nawfal

Cela fonctionne grâce à initialiseurs de collection qui nécessitent essentiellement que la collection implémente une méthode Add et qui fera le travail pour vous.

6
vc 74

La syntaxe de type tableau est transformée en une série d'appels Add().

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 un initialiseur.

public class MyClass
{   
    public MyClass()
    {   
        _list = new List<string>();
    }
    private IList<string> _list;
    public IList<string> MyList 
    { 
        get
        { 
            return _list;
        }
    }
}
//In some other method
var sample = new MyClass
{
    MyList = {"a", "b"}
};

Ce code fonctionnera parfaitement, bien que 1) MyList soit 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 initialiseur d'objet, le compilateur transforme toujours toute syntaxe similaire à {} En une série d'appels Add() qui sont parfaitement légaux même en lecture seule champ.

0
yoel halb