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

本文关键字:泛型类 帮助 | 更新日期: 2023-09-27 18:16:57

我正在学习Nhibernate 3.0。在其中一个示例代码示例中,它创建了一个抽象基实体类:

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> "。

请帮我理解一下,我对这个泛型类真的很困惑。

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

你说的

customer继承自"Entity",此"Entity"以"customer"为T,但该客户不是"实体"

这没有任何意义,因为这就是继承的含义。它建立了一种"是"的关系。所以实际上Customer就是Entity

对不起,这是基于剥离泛型的代码,因为它不在代码块中。

同样的原则仍然有效。这有点令人困惑因为它看起来像一个递归定义,但它不是。

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

例如它有一个方法叫做
public IEnumerable<T> GetEntities() 

返回它自己的实例列表。它需要那个方法返回具体类型而不是基类型。在Customer类中,这个方法是

public IEnumerable<Customer> GetEntities<Customer>() 

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

这只是一个如何使用的例子,我不知道它实际上是如何使用的

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

问题是,当20个不同的类从一个基类继承时,这个基类实际上并不知道谁在使用它的功能。这是一种让基类知道"Customer"正在使用它的方法的方法,以便它可以专门满足"Customer"的需求。

where子句指定了要代替 T的类型必须遵守的条件。因此,如果类型是Customer,如第二行代码中的Entity<Customer>,则条件是Customer : Entity<Customer>…也就是说,Customer必须是Entity<Customer>的子类,否则会出现编译错误。事实上,在第二行代码中,它也是这样声明的。

将此应用于您所写的内容:

此" Entity<Customer> "以"Customer"作为T

我是这样说的:Entity<Customer>Entity<T>的实例化,用Customer代替TT只是某种类型的占位符;它是一个类型参数

但是这个客户不是" Entity<T> "

我们也可以用SomeType代替T来编写抽象方法声明。条件是,为了实例化Entity< SomeType >SomeType必须是Entity< SomeType >的子类。将SomeType替换为Customer,即表示Customer必须是Entity<Customer>的子类,并且它是。

如果您理解T只是一个参数,并且在Entity<Customer>的情况下将Customer替换为它,那么我不理解为什么您说'这个客户不是' Entity<T> ' ',因为Customer : Entity<Customer>声明它就是这样(Entity<T>定义中的每次出现都用Customer替换T)。

显示如何使用这种继承的示例:

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