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();

我认为这是另一个棘手的通用方差问题,但即使在阅读了 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 中你可以 return CollectionBase<ItemBase>,但我还没有在 Beta 上尝试过。

于 2009-09-20T10:30:01.260 回答