Wie ein Verfahren zu erklären, dass eine generische Sammlung von „etwas“ zurückgibt (C #)
-
12-09-2019 - |
Frage
ich eine Hierarchie der generischen Collection-Klassen verwenden, die von einer abstrakten Basisklasse ableiten Unternehmen Posten zu speichern, die auch von einer abstrakten Basisklasse ableiten:
abstract class ItemBase { }
class MyItem : ItemBase
{
public MyItem()
{
}
}
abstract class CollectionBase<T> : Collection<T> where T : ItemBase, new() { }
class MyCollection : CollectionBase<MyItem> { }
Die Ziele dieses Modells sind die Mitglieder einer Klasse von Collection
Jetzt möchte ich eine Factory-Methode erstellen, die eine Instanz einer Klasse von Collection abgeleitet zurück
public CollectionBase<T> CreateCollection<T>();
... oder vielleicht ...
public T Create CreateCollection<T>();
Allerdings ist das Problem, dass die anrufende Routine nicht weiß, was „T“ erforderlich ist. Es ist die Factory-Methode selbst, dass die spezifische Art der Sammlung bestimmen müssen zurückzukehren. Also brauche ich eine nicht-generische Methode Signatur, die sagt, dass „der Rückgabetyp von Collection zufließen wird
public CollectionBase<> CreateCollection();
Ich nehme an, das andere dieser heikle generischen Varianz Fragen, aber auch nach über das Thema Eric Lippert umfangreiche Erklärung zu lesen, bin ich immer noch unklar, ob das, was ich versuche sein machbar in C # 4.0 wahrscheinlich zu tun ist, und ob es eine einfache Abhilfe ist in C # 3.0.
Vielen Dank im Voraus für Ihre Ideen.
Lösung
Lassen Sie uns sagen, dass die Factory-Methode ein einzelnes Element kreierten. Sie müßten:
public ItemBase CreateItem();
Sie haben ItemBase
zu verwenden, weil Sie nichts mehr spezifisch wissen können. Unter Anwendung dieses Prinzips auf die Erhebungsmethode erhalten Sie:
public CollectionBase<ItemBase> CreateCollection();
Aufgrund der fehlenden Varianz, benötigen Sie einen Adapter-Klasse, die von CollectionBase<ItemBase>
ableitet und wickelt die aktuelle Kollektion, die erstellt wird.
In C # 4.0 Sie würden nur die tatsächliche Sammlung zurück.
Edit: Die Fabrik könnte so aussehen, mit dem Adapter eingebettet:
public class CollectionFactory
{
public CollectionBase<ItemBase> CreateCollection()
{
if(someCondition)
{
return CreateAdapter(new MyCollection());
}
else
{
return CreateAdapter(new MyOtherCollection());
}
}
private static CollectionAdapter<T> CreateAdapter<T>(CollectionBase<T> collection) where T : ItemBase, new()
{
return new CollectionAdapter<T>(collection);
}
private class CollectionAdapter<T> : CollectionBase<ItemBase> where T : ItemBase, new()
{
private CollectionBase<T> _collection;
internal CollectionAdapter(CollectionBase<T> collection)
{
_collection = collection;
}
// Implement CollectionBase API by passing through to _collection
}
}
Andere Tipps
Wahrscheinlich, was Sie brauchen, ist:
public CollectionBase<Object> CreateCollection();
Da jede Klasse direkt oder indirekt aus der Objektklasse erbt.
Ich habe nicht wirklich das getan, und entschuldige mich, wenn es vollständig naiv, aber ...
public CollectionBase<Object> CreateCollection();
Wenn Sie es wirklich wollen, etwas sein, könnte man nur ICollection zurückkehren, und dann die Verbraucher könnte die .Cast<ItemBase>()
Erweiterung Methode aufrufen, wie sie benötigen.
Von dem, was ich verstehe, in .NET 4.0 Sie CollectionBase<ItemBase>
zurückzukehren wären in die Lage, aber ich habe es nicht auf der Beta noch nicht ausprobiert.