57 votes

Pourquoi les initialiseurs de collection C # fonctionnent-ils de cette façon?

Je regardais C# initialiseurs de la collection et a constaté la mise en œuvre pour être très pragmatique, mais aussi très différent de tout autre chose en C#

Je suis en mesure de créer un code comme ceci:

using System;
using System.Collections;

class Program
{
    static void Main()
    {
    	Test test = new Test { 1, 2, 3 };
    }
}

class Test : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
    	throw new NotImplementedException();
    }

    public void Add(int i) { }
}

Depuis que j'ai satisfait aux exigences minimales pour le compilateur (mise en œuvre en IEnumerable et public void Add) cela fonctionne mais n'a évidemment aucune valeur.

Je me demandais ce qui a empêché l'équipe C# à partir de la création d'un plus strict des exigences? En d'autres termes pourquoi, pour que cette syntaxe pour compiler, le compilateur ne pas exiger que le type de mettre en oeuvre ICollection? Qui me semble plus dans l'esprit de l'autre C# caractéristiques.

90voto

Bevan Points 20976

Votre observation est sur place - en fait, elle ressemble à celle faite par Mads Torgersen, Microsoft Langage C# H.

Mads fait un post en octobre 2006, sur ce sujet, intitulé qu'Est Ce qu'une Collection? dans lequel il écrit:

Admis, nous avons fait sauter dans le premier version du framework avec Système.Les Collections.ICollection, qui est à côté de rien. Mais nous l'avons fixé jusqu' assez bien lorsque les génériques sont venus le long de dans .NET framework 2.0: Système.Les Collections.Génériques.ICollection vous permet d'Ajouter et de Supprimer des éléments, les énumérer, dénombrer et vérifier pour l'adhésion.

De toute évidence, à partir de là, tout le monde serait d' mettre en œuvre ICollection<T> à chaque fois ils en font une collection, non? De ne pas faire. Voici comment nous avons utilisé LINQ pour en savoir à propos de ce que les collections sont vraiment, et comment ça nous a fait changer notre langue conception en C# 3.0.

Il s'avère qu'il y a seulement 14 implémentations de ICollection<T> dans le cadre, mais les 189 classes qui implémentent IEnumerable et ont un public Add() méthode.

Il y a un caché avantage de cette approche - si ils avaient, en se basant sur l' ICollection<T> interface, il y aurait eu exactement pris en charge Add() méthode.

En revanche, l'approche qu'ils ne prennent signifie que les initialiseurs de la collection de la forme des ensembles d'arguments en faveur de l' Add() méthodes.

Pour illustrer, nous allons étendre votre code légèrement:

class Test : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        throw new NotImplementedException();
    }

    public void Add(int i) { }

    public void Add(int i, string s) { }
}

Vous pouvez maintenant écrire ceci:

class Program
{
    static void Main()
    {
        Test test 
            = new Test 
            {
                1, 
                { 2, "two" },
                3 
            };
    }
}

9voto

DavidN Points 2941

J'ai pensé à ça aussi, et la réponse qui me satisfait le plus, c'est que ICollection a beaucoup de méthodes autres que d'Ajouter, comme: Clair, Contient, CopyTo, et Retirez-la. La suppression d'éléments ou de compensation n'a rien à voir avec le fait d'être en mesure de soutenir l'initialiseur d'objet de syntaxe, vous avez besoin d'une Add().

Si le cadre a été conçu granulaire assez, et il y avait un ICollectionAdd l'interface, puis il aurait eu un "parfait". Mais honnêtement, je ne pense pas que cela aurait ajouté beaucoup de valeur, d'avoir une méthode par l'interface. IEnumerable + Ajouter semble comme un hackish approche, mais quand vous pensez à ce sujet, c'est une meilleure alternative.

EDIT: Ce n'est pas le seul moment C# a abordé un problème avec ce type de solution. Depuis .NET 1.1, foreach utilise duck-typing pour énumérer une collection, tous vos besoins de la classe à mettre en œuvre est GetEnumerator, MoveNext et Actuel. Kirill Osenkov a un post qui demande à votre question.

3voto

Eldritch Conundrum Points 1683

(Je sais que j'ai 3 ans de retard sur ce sujet, mais je n'étais pas satisfait de la les réponses.)

pourquoi, pour que cette syntaxe pour compiler, le compilateur ne pas exiger que le type de mettre en œuvre ICollection?

Je vais revenir sur votre question: Que serait-il si le compilateur a des exigences qui ne sont pas vraiment nécessaires?

Non-ICollection classes peuvent aussi bénéficier de la collection de l'initialiseur de la syntaxe. Considérer les classes qui permettent d'ajouter des données, sans permettre l'accès à déjà ajouté des données.

Personnellement, j'aime utiliser l' new Data { { ..., ... }, ... } de la syntaxe pour ajouter un peu, DSL-comme l'aspect le code de mes tests unitaires.

En fait, je préfère affaiblir l'exigence, afin que je puisse utiliser la belle apparence de la syntaxe, sans même avoir à se soucier de mise en œuvre IEnumerable. Initialiseurs de la Collection sont un pur sucre syntaxique pour Ajouter(), ils ne devraient pas demander n'importe quoi d'autre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X