2011-12-06 56 views
4

我正在学习Nhibernate 3.0。在示例代码的例子之一,它创建了一个抽象基实体类:需要帮助来理解这个C#泛型类

public abstract class Entity<T> where T : Entity<T> 

然后,使Customer实体从Entity基类继承:

public class Customer : Entity<Customer> 

我知道这是一个抽象的通用类,它使用where关键字来确保类型TEntity<T>,这是我感到困惑的地方。从

Customer继承 “Entity<Customer>”,这个 “Entity<Customer>” 以 “Customer” 为T,但这Customer不是 “Entity<T>”。

请帮我理解这一点,我被这个泛型类弄糊涂了。

+0

你能否把一个链接到你的实际的例子,如果例子是在网络上的某个地方?我有搜索,但我找不到它。我自己也有这个问题。干杯。 – Greenonline

回答

8

你说

客户从 “实体” 继承,这个 “实体” 以 “客户” 为T, 但是这个客户是不是 “实体”

不有意义的,因为这就是继承的含义。它确立了“是一种”关系。所以其实一 CustomerEntity

对不起这是基于与剥离出来,因为它在一个代码块不是泛型的代码。

虽然相同的原理仍然有效。这有点令人困惑,因为它看起来像是一个递归定义,但事实并非如此。

把它想象为Customer继承自Entity恰好存在依赖于泛型参数本身的方法或字段,例如, Customer。我不熟悉NHibernate,所以我不知道Entity<T>的其余部分是什么样的,但我想它有一些方法使用它自己的类型作为通用参数。

例如说有一个叫

public IEnumerable<T> GetEntities() 

方法返回它自己的实例的列表。它需要该方法来返回具体类型而不是基类型。所以在Customer类,该方法是

public IEnumerable<Customer> GetEntities<Customer>() 

如果没有泛型参数,它只能返回IEnumerable<Entity>

这只是一个,我不它是如何被使用的案例不知道它是如何使用的。

+0

对不起,它没有任何意义,因为我真的很困惑,并试图了解它是如何工作的。你能纠正我说的更有意义吗? – qinking126

+0

@feelexit你说“客户”不是“实体”但它是。该班级被宣布为“公共班级客户:实体”,这意味着“客户”***是***实体。 – Davy8

0

where子句指定的条件是代入代替T必须服从。因此,如果类型是Customer,如在该第二行代码中的Entity<Customer>,则条件是Customer : Entity<Customer> ......即Customer必须是Entity<Customer>的子类别,否则存在编译错误。事实上,它在第二行代码中又如此声明。

这适用于你写的:

这个“Entity<Customer>”以“客户”为T

这是我会怎么说的:Entity<Customer>Customer用于取代Entity<T>一个实例TT只是某种类型的占位符;这是一个类型参数

但是这位客户是不是“Entity<T>

我们可以同样出色SOMETYPE而不是T写抽象方法声明。的条件是,以实例化Entity<SOMETYPE>SOMETYPE必须Entity<SOMETYPE>的子类。用Customer代替SomeType,即Customer必须是Entity<Customer>的一个子类,它是。

如果你明白T只是一个参数,那Customer是在Entity<Customer>的情况下取代它,那么我不明白为什么你说“这个客户是不是‘Entity<T>’”,因为Customer : Entity<Customer>声明它只是(CustomerEntity<T>的定义中每次出现时都替换为T)。

1

当您考虑基础“实体”类尝试执行的操作时,它会更有意义。我对nhibernate也不熟悉,但我会想象其中一种方法可能类似于Save()方法。因此,您创建的任何从Entity类继承的类都将继承Save()方法,使您不必为每个业务对象重写它。但是,基本实体类必须知道您要保存的对象类型。它可以使用反射,但是在这里它使用泛型来让你告诉它是什么类的继承实体。

问题是,当20个不同的类从基类继承时,该基类并不知道谁在使用它的功能。这是一种让基类知道“客户”正在使用其方法的方法,以便它可以专门迎合“客户”的需求。

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