需要帮助来理解这个C#泛型类

时间:2011-12-06 02:31:00

标签: c# nhibernate generics generic-constraints

我正在学习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>”。

请帮助我理解这一点,我对这个通用类感到困惑。

4 个答案:

答案 0 :(得分:8)

你说

  

客户继承自“实体”,此“实体”将“客户”视为T,   但这个客户不是“实体”

这没有任何意义,因为这就是继承意味着什么。它建立了“是一种”关系。事实上,CustomerEntity

很抱歉,这是基于代码被剥离的代码,因为它不在代码块中。

同样的原则仍然有效。它只是有点混乱,因为它看起来像是递归定义,但事实并非如此。

将其视为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代替TT只是某种类型的占位符;它是一个参数

  

但此客户不是“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();
}