2

抽象基本クラスから派生するジェネリック コレクション クラスの階層を使用して、抽象基本クラスからも派生するエンティティ項目を格納しています。

abstract class ItemBase { }

class MyItem : ItemBase
{
    public MyItem()
    {
    }
}


abstract class CollectionBase<T> : Collection<T> where T : ItemBase, new() { }

class MyCollection : CollectionBase<MyItem> { }

このモデルの目的は、CollectionBase<T> から派生したクラスのメンバーに厳密な型規則を適用し、これらのメンバーが既定のパブリック コンストラクターを持つことを保証することです。これまでのところ、動作します。

ここで、CollectionBase<T> から派生したクラスのインスタンスを返すファクトリ メソッドを作成したいと考えています。通常のアプローチは次のようになることを理解しています。

public CollectionBase<T> CreateCollection<T>();

... または多分 ...

public T Create CreateCollection<T>();

ただし、問題は、呼び出し元のルーチンが必要な "T" を認識していないことです。返す特定のタイプのコレクションを決定する必要があるのは、ファクトリ メソッド自体です。したがって、「戻り値の型は CollectionBase<T> から派生する」という非ジェネリック メソッド シグネチャが必要です。私はこのようなことを想定しています(合法であれば)...

public CollectionBase<> CreateCollection();

これは厄介なジェネリック分散の問題の 1 つだと思いますが、この件に関する Eric Lippert の広範な説明を読んだ後でさえ、私がやろうとしていることが C# 4.0 で実行可能であるかどうか、および単純な方法があるかどうかはまだわかりません。 C# 3.0 での回避策。

あなたのアイデアを前もってありがとう。

4

4 に答える 4

1

ファクトリ メソッドが単一のアイテムを作成していたとしましょう。次のようになります。

public ItemBase CreateItem();

ItemBaseより具体的なことを知ることができないため、使用する必要があります。この原則をコレクション メソッドに適用すると、次のようになります。

public CollectionBase<ItemBase> CreateCollection();

CollectionBase<ItemBase>差異がないため、作成された実際のコレクションから派生してラップするアダプター クラスが必要です。

C# 4.0 では、実際のコレクションを返すだけでした。

編集:アダプタが埋め込まれたファクトリは次のようになります。

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
    }
}
于 2009-09-20T10:32:40.770 に答える
0

おそらく必要なものは次のとおりです。

public CollectionBase<Object> CreateCollection();

すべてのクラスは Object クラスから直接的または間接的に継承するためです。

于 2009-09-20T10:27:27.600 に答える
0

私は実際にこれを行ったわけではなく、完全にナイーブである場合は申し訳ありませんが...

public CollectionBase<Object> CreateCollection();

?

于 2009-09-20T10:29:42.743 に答える
0

本当に何でもしたい場合は、ICollection を返すだけで、消費者は必要に応じて.Cast<ItemBase>()拡張メソッドを呼び出すことができます。

私が理解していることから、.NET 4.0 では を返すことができますがCollectionBase<ItemBase>、ベータ版ではまだ試していません。

于 2009-09-20T10:30:01.260 に答える