使用泛型和支持子类跟踪实例

时间:2009-12-03 22:28:42

标签: c# generics casting

我已经定义了以下泛型类

public class ManagedClass<T> where T : ManagedClass<T>
{
    static ManagedClass()
    {
        Manager = new ObjectManager<T>();
    }
    public static ObjectManager<T> Manager { get; protected set; }

    public ManagedClass()
    {
        Manager.Add( (T)this );
    }
}

我的想法是我可以像这样使用它:

class Product : ManagedClass<Product> {}

现在我可以对第7个产品做点什么了:

Product.Manager.GetById(7).DoSomething();

如果我尝试使用派生类,则会出现问题:

class ExtendedProduct : Product {}

现在ExtendedProduct.Manager有一个'Products'列表,如果我想使用我添加到ExtendedProduct(DoSomethingElse)的新函数,我必须像以下那样转换我得到的对象:

((ExtendedProduct)ExtendedProduct.Manager.GetById(7)).DoSomethingElse();

这有点难看,而使用泛型的全部意义在于避免施法。我想我可以在派生类中添加一个静态构造函数来设置Manager = new ObjectManager()并在派生类构造函数中添加一个新的Manager.addObject(this),但似乎应该有一些更好的方法来执行此操作仿制药。有什么建议吗?

2 个答案:

答案 0 :(得分:1)

问题是ExtendedProduct.ManagerProduct.Manager是一回事;经理对象的行为不同,取决于从哪里访问。

我能想到的几种可能性:

  1. 通过使其成为通用的方法隐藏GetById方法中的类型转换: Product.Manager.GetById<ExtendedProduct>(7).DoSomethingElse();

  2. 每个子类使用一个ObjectManager个实例,如果需要,可以私下连接它们

  3. 选项1让我想起NHibernate的ICriteria接口。它实际上与类型转换相同,但有点难以意外破坏。

答案 1 :(得分:1)

你真正遇到的是泛型的弱点。一旦你的班级解决了它用于泛型的类型,你就会受到一些限制。

通常情况下,我会说依赖注射会成为一个救世主,但由于问题的方法是static,所以这会混淆水域。

我认为最好的办法是让ObjectManager类为你完成工作:

static public class ObjectManager<T>
{
    ... the code that already exists in ObjectManager ...

    static public U GetById<U>(long id)
    {
        object obj = GetById(id);
        if (obj is U)
            return (U)obj;
        return default(U);
    }
}

然后,在您的代码中:

ExtendedProduct.Manager.GetById<ExtendedProduct>(7).DoSomethingElse();

它并不比铸造更优雅,但可能是使用Generics的唯一解决方案之一。