Ist es in Ordnung einen int für den Schlüssel in einem KeyedCollection zu verwenden
-
03-07-2019 - |
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 .
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
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
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.