我正在学习Nhibernate 3.0。在其中一个示例代码示例中,它创建了一个抽象基本实体类:
public abstract class Entity<T> where T : Entity<T>
然后,使Customer
实体继承自Entity
基类:
public class Customer : Entity<Customer>
我理解它是一个抽象的泛型类,它使用where
关键字来确保T
类型为Entity<T>
,这是我感到困惑的地方。
Customer
继承自“Entity<Customer>
”,此“Entity<Customer>
”将“Customer
”视为T
,但此Customer
不是“Entity<T>
”。
请帮助我理解这一点,我对这个通用类感到困惑。
答案 0 :(得分:8)
你说
客户继承自“实体”,此“实体”将“客户”视为T, 但这个客户不是“实体”
这没有任何意义,因为这就是继承意味着什么。它建立了“是一种”关系。事实上, Customer
是Entity
很抱歉,这是基于代码被剥离的代码,因为它不在代码块中。
同样的原则仍然有效。它只是有点混乱,因为它看起来像是递归定义,但事实并非如此。
将其视为Customer
继承自Entity
恰好是依赖于通用参数本身的方法或字段,例如Customer
。我不熟悉NHibernate所以我不知道Entity<T>
的其余部分是什么样的,但我想它有一些方法使用它自己的类型作为泛型参数。
比如说它有一个名为
的方法public IEnumerable<T> GetEntities()
返回了它自己的实例列表。它需要该方法来返回具体类型而不是基类型。所以在Customer
类中,该方法将是
public IEnumerable<Customer> GetEntities<Customer>()
如果它没有通用参数,则只能返回IEnumerable<Entity>
这只是一个如何使用的例子,我不知道它是如何使用的。
答案 1 :(得分:1)
当您考虑基础'Entity'类尝试执行哪些操作时,它会更有意义。我也不熟悉nhibernate,但我想其中一种方法可能类似于Save()方法。因此,您创建的任何继承自Entity类的类都将继承Save()方法,从而使您不必为您创建的每个业务对象重写它。但是,Base实体类必须知道您要保存的对象类型。它可以使用反射,但在这里它使用泛型来告诉它继承实体的类是什么类。
事实是,当20个不同的类继承自基类时,该基类并不真正了解谁在使用其功能。这是一种让基类知道“客户”正在使用其方法的方法,以便它可以专门满足“客户”的需求。
答案 2 :(得分:0)
where
子句指定T
的替换类型必须遵守的条件。因此,如果类型为Customer
,如第二行代码中的Entity<Customer>
,则条件为Customer : Entity<Customer>
...即,Customer
必须是子类Entity<Customer>
,否则会出现编译错误。事实上它已经在第二行代码中声明了。
将此应用于您所写的内容:
这个“
Entity<Customer>
”将“客户”视为T
以下是我的说法:Entity<Customer>
是Entity<T>
的实例化,Customer
代替T
。 T
只是某种类型的占位符;它是一个参数。
但此客户不是“
Entity<T>
”
我们也可以用 SomeType 而不是T
编写抽象方法声明。条件是,为了实例化Entity<
SomeType >
, SomeType 必须是Entity<
SomeType的子类 >
。将Customer
替换为 SomeType ,即Customer
必须是Entity<Customer>
的子类,并且它是。
如果您了解T
只是一个参数,并且在Customer
的情况下用Entity<Customer>
代替它,那么我不会理解为什么你说“这个客户不是”Entity<T>
“',因为Customer : Entity<Customer>
声明它就是那个(Customer
代替T
Entity<T>
)的定义。
答案 3 :(得分:0)
显示如何使用此类继承的示例:
class Creatable<T> where T:Creatable<T>, new()
{
pulibc static T Create()
{
T t = new T(); // we know to call new due new() constraint
t.FinishCreation(); // we know that T implements this method due Creatable<T> constraint
return t;
}
public void SomeOtherUsefulsOperation(){};
protected virtual void FinishCreation(){};
}
class Child:Creatable<Child>
{
public Child(){};
protected override void FinishCreation(){/*do something special for this type */};}
}
// somewhere else
void DoSomething<T>() where T:Creatable<T>
{
T item = Creatable<T>.Create();
item.SomeOtherUsefulOperation();
}