我已经定义了以下泛型类
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),但似乎应该有一些更好的方法来执行此操作仿制药。有什么建议吗?
答案 0 :(得分:1)
问题是ExtendedProduct.Manager
与Product.Manager
是一回事;经理对象的行为不同,取决于从哪里访问。
我能想到的几种可能性:
通过使其成为通用的方法隐藏GetById
方法中的类型转换:
Product.Manager.GetById<ExtendedProduct>(7).DoSomethingElse();
每个子类使用一个ObjectManager
个实例,如果需要,可以私下连接它们
选项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的唯一解决方案之一。