Frage

Oft brauche ich eine Sammlung von nicht-sequenziellen Objekten mit numerischen Kennungen. Ich mag die KeyedCollection für diese, aber ich denke, es ist ein gravierender Nachteil. Wenn Sie einen int für den Schlüssel verwenden, können Sie keinen Zugriff mehr Mitglieder der Sammlung durch ihren Index (Sammlung [index] ist jetzt wirklich Sammlung [key]). Ist dies ein ernstes Problem genug mit dem int als Schlüssel zu vermeiden? Was wäre eine bessere Alternative sein? (Vielleicht int.ToString ()?)

Ich habe dies getan, bevor ohne größere Probleme, aber vor kurzem traf ich einen fiesen Haken, wo die XML-Serialisierung gegen eine KeyedCollection tut nicht Arbeit, wenn der Schlüssel ein int ist, aufgrund ein Fehler in .NET .

War es hilfreich?

Lösung

Im Grunde müssen Sie entscheiden, ob Benutzer der Klasse wahrscheinlich durch die Tatsache verwechselt werden, dass sie nicht zum Beispiel tun:

for(int i=0; i=< myCollection.Count; i++)
{
    ... myCollection[i] ...
}

obwohl sie können natürlich Verwendung foreach, oder eine Besetzung verwenden:

for(int i=0; i=< myCollection.Count; i++)
{
    ... ((Collection<MyType>)myCollection)[i] ...
}

Es ist keine leichte Entscheidung, da es leicht zu heisenbugs führen kann. Ich beschloss, es in einem meiner Anwendungen zu ermöglichen, in denen der Zugang von den Benutzern der Klasse fast ausschließlich von Schlüssel war.

Ich bin nicht sicher, ich für eine gemeinsame Klassenbibliothek obwohl dies tun würde: im Allgemeinen ich vermeiden würde eine KeyedCollection in einer öffentlichen API aussetzt: Statt würde ich IList in einem öffentlichen API aussetzen, und die Verbraucher von die API, die Schlüssel Zugang benötigen, können ihre eigenen internen KeyedCollection mit einem Konstruktor definieren, die mit ihm eine IEnumerable und füllt die Sammlung nimmt. Das heißt, Sie können ganz einfach eine neue KeyedCollection aus einer Liste aus einem API abgerufen bauen.

Im Hinblick auf die Serialisierung, gibt es auch ein Leistungsproblem , die ich zu melden Microsoft Connect : die KeyedCollection unterhält einen internen Wörterbuch sowie eine Liste, und serialisiert beide - es ausreichend ist, um die Liste zu serialisiert als das Wörterbuch leicht auf Deserialisierung neu erstellt werden kann

.

Aus diesem Grund sowie der XmlSerialization Fehler, würde ich empfehlen, vermeiden Sie eine KeyedCollection Serialisierung -. Statt nur die KeyedCollection.Items Liste serialisiert

Ich mag es nicht der Vorschlag der int Schlüssel in einer anderen Art wickelt. Es scheint mir falsch Komplexität einfach hinzufügen, so dass eine Art kann als ein Element in einem KeyedCollection verwendet werden. Ich würde einen String-Schlüssel verwenden (ToString), anstatt dies zu tun -. Das ist eher wie die VB6 Klasse Collection

FWIW, fragte ich

Andere Tipps

Eine einfache Lösung könnte sein, die int in einer anderen Art wickeln einen bestimmten Typen für die Überladungsauflösung zu schaffen. Wenn Sie eine struct verwenden, wird dieser Wrapper keinen zusätzlichen Aufwand hat:

struct Id {
    public int Value;

    public Id(int value) { Value = value; }

    override int GetHashCode() { return Value.GetHashCode(); }

    // … Equals method.
}

Es wäre am besten, eine GetById(int) Methode zu einer Sammelstelle Typ hinzuzufügen. Collection<T> kann stattdessen verwendet werden, wenn Sie keine anderen Schlüssel müssen die darin enthaltenen Objekte für den Zugriff auf:

public class FooCollection : Collection<Foo>
 { Dictionary<int,Foo> dict = new Dictionary<int,Foo>();

   public Foo GetById(int id) { return dict[id]; }

   public bool Contains(int id) { return  dict.Containskey(id);}

   protected override void InsertItem(Foo f)
    { dict[f.Id] = f;
      base.InsertItem(f);
    }

   protected override void ClearItems()
    { dict.Clear();
      base.ClearItems();
    }

   protected override void RemoveItem(int index)
    { dict.Remove(base.Items[index].Id);
      base.RemoveItem(index);
    }

   protected override void SetItem(int index, Foo item)
    { dict.Remove(base.Items[index].Id);
      dict[item.Id] = item;
      base.SetItem(index, item);
    }
 }









 }

Der Schlüssel in einem KeyedCollection sollte eindeutig sein und schnell ableitbar von dem Objekt gesammelt werden. Bei einer Person-Klasse, zum Beispiel, könnte es die SSN Eigenschaft sein oder vielleicht sogar Vornamen und Nachnamen Eigenschaften verketten (wenn das Ergebnis eindeutig bekannt ist). Wenn eine ID zu Recht ein Feld des Objekts wird gesammelt, als es ein gültiger Kandidat für den Schlüssel. Aber vielleicht versuchen, es als String Casting statt, die Kollision zu vermeiden.

scroll top