需要帮助来理解这个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
关键字来确保类型T
是Entity<T>
,这就是我感到困惑的地方。
Customer
继承自" Entity<Customer>
",此" Entity<Customer>
"以" Customer
"作为T
,但此" Customer
"不是" Entity<T>
"。
请帮我理解一下,我对这个泛型类真的很困惑。
你说的
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
代替T
。T
只是某种类型的占位符;它是一个类型参数。
但是这个客户不是"
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();
}