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 und zu garantieren, abgeleitet strengen Typ Disziplin zu erzwingen, dass diese Elemente einen Standard öffentlichen Konstruktor haben. Bis jetzt funktioniert es.

Jetzt möchte ich eine Factory-Methode erstellen, die eine Instanz einer Klasse von Collection abgeleitet zurück . Ich verstehe, dass der üblicher Ansatz wäre:

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 “. Ich stelle mir vor so etwas wie dies (wenn es legal wäre) ...

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.

War es hilfreich?

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top