2009-09-02 8 views
3

J'ai une classe dérivée du Dictionnaire. J'ai besoin de cette classe pour simuler un HashSet, parce que Silverlight ne connaît pas HashSets et mes classes font un usage intensif de HashSets. J'ai donc décidé d'échanger le HashSet avec le dictionnaire. Pour utiliser plus mes cours avec tous les HashSet-objets, je tente de faire une classe HashSet personnalisée, qui est dérivé du Dictionnaire et remplacer toutes les méthodes relavant comme Add-méthode:Activer foreach pour une classe dérivée du Dictionnaire

class HashSet<T> : Dictionary<T, object> 
{ 

    public override void Add(T element) 
    { 
     base.Add(element, null); 
    } 
} 

Maintenant je dois permettre la boucle foreach pour ma nouvelle classe HashSet. Évidemment, ma classe renvoie un KeyValuePair dans une boucle foreach, mais j'ai besoin de T comme type de retour. Quelqu'un peut-il me dire, quoi et comment j'ai besoin de remplacer la classe de base Dictionary?

Merci à l'avance, Frank

+0

Très bonne question, en effet. La réponse de Jon Skeet aide mon code à avoir plus de sens et être utilisable de notre point de vue. –

Répondre

15

Je vous suggère fortement que vous ne pas dérivent de Dictionary en premier lieu. Utilisez la composition au lieu de l'héritage. Si vous dérivez de Dictionary, les gens peuvent utiliser votre classe comme un dictionnaire de paires clé/valeur au lieu d'un ensemble.

Alors, vous concevez votre classe avec un dictionnaire intérieur:

public sealed class DictionaryBackedSet<T> : IEnumerable<T> 
{ 
    private readonly Dictionary<T, int> dictionary = new Dictionary<T, int>(); 

    public IEnumerator<T> GetEnumerator() 
    { 
     return dictionary.Keys.GetEnumerator(); 
    } 

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

    public bool Add(T item) 
    { 
     if (Contains(item)) 
     { 
      return false; 
     } 
     dictionary.Add(item, 0); 
     return true; 
    } 

    public bool Contains(T item) 
    { 
     return dictionary.ContainsKey(item); 
    } 

    // etc 
} 

Vous pouvez également créer un struct vide comme argument de type de valeur pour le dictionnaire:

public struct Empty {} 

Cela peut sauve un peu de mémoire. Je vous inquiétez pas à ce sujet pour l'instant si - et si vous rédigez le dictionnaire au lieu de héritant de lui, faisant que le changement ne se cassera plus tard rien :)

Ce serait bien si vous pouviez utiliser System.Void à cet effet (c.-à-utiliser Dictionary<T, Void>), mais C# ne vous laissera pas faire ça :(

+0

Si vous n'utilisez pas votre structure vide, l'exemple ne devrait-il pas utiliser les bits sur int? – stevehipwell

+0

Merci Jon! Je vais suivre vos suggestions et utiliser la composition au lieu de l'héritage. Les deux méthodes GetEnumerator sont-elles suffisantes pour activer foreach? Je pensais avoir besoin d'implémenter (au moins) Current, MoveNext et Reset. – Aaginor

+0

@aaginor: Cela implémenterait 'IEnumerator'. Vous n'avez pas besoin de faire cela, car vous pouvez utiliser la séquence de clés retournée par le dictionnaire lui-même. Vous êtes juste piggy-backing. –

2

Je pense que vous devez mettre en œuvre IEnumerable (Of T), qui travaillerait en interne avec la collection Keys.

IDictionary implémente déjà IEn umerable (Of KeyValuePair (Of TKey, TValue)), mais peut-être est-il également possible de l'implémenter pour un autre type?

Je suis avec Jon re essayant de sous-classer le dictionnaire - éviter si vous le pouvez, la composition est un motif de conception beaucoup plus approprié.

+1

Collection de clés, pas de collection de valeurs. La collection Values ​​serait juste null (ou 0, ou peu importe). –

+0

Edité, totalement manqué que dans son code. – richardtallent

3

Je suggère que plutôt que d'hériter du dictionnaire, vous l'enveloppez. Un HashSet n'est pas un dictionnaire.

Questions connexes