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

发布于 2024-12-19 14:31:58 字数 642 浏览 1 评论 0原文

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

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

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

public class Customer : Entity<Customer>

我知道它是一个抽象泛型类,并且它使用 where 关键字来确保类型 TEntity,这就是我感到困惑的地方。

Customer 继承自“Entity”,此“Entity”将“Customer”作为T,但此Customer 不是“Entity”。

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

I am learning Nhibernate 3.0. In one of the sample code examples, it creates an abstract base entity class:

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

then, make the Customer entity inherit from the Entity base class:

public class Customer : Entity<Customer>

I understand it's an abstract generic class, and it is using the where keyword to make sure the type T is Entity<T>, this is where I get confused.

Customer inherits from "Entity<Customer>", this "Entity<Customer>" takes "Customer" as T, but this Customer is not "Entity<T>".

Please help me to understand this, I'm really confused by this generic class.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

破晓 2024-12-26 14:31:58

你说

customer继承自“Entity”,这个“Entity”将“Customer”作为T,
但该客户不是“实体”

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

抱歉,这是基于删除了泛型的代码,因为它不在代码块中。

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

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

举例来说,它有一个名为的方法

public IEnumerable<T> GetEntities() 

,该方法返回它自己的实例的列表。它需要该方法返回具体类型而不是基本类型。因此,在 Customer 类中,该方法将是

public IEnumerable<Customer> GetEntities<Customer>() 

如果它没有通用参数,它只能返回 IEnumerable

这只是一个示例可以使用,不知道实际使用起来如何。

You said

customer inherits from "Entity", this "Entity" takes "Customer" as T,
but this customer is not "Entity"

That doesn't make any sense because that's what inheritance means. It establishes an "is a" relationship. So in fact a Customer is an Entity

Sorry that was based on the code with the generics stripped out because it wasn't in a code block.

The same principle is still valid though. It's just a little confusing because it looks like it's a recursive definition, but it's not.

Think of it as Customer inherits from Entity There just happens to be methods or fields that depend on the generic parameter being itself e.g. Customer. I'm not familiar with NHibernate so I don't know what the rest of Entity<T> looks like, but I imagine it has some methods that use it's own type as a generic parameter.

Say for instance it has a method called

public IEnumerable<T> GetEntities() 

that returned a list of it's own instances. It needs that method to return the concrete type rather than the base type. So in the Customer class, that method would be

public IEnumerable<Customer> GetEntities<Customer>() 

If it didn't have the generic parameter, it could only return IEnumerable<Entity>

That's just an example of how it could be used, I don't know how it's actually used.

一曲琵琶半遮面シ 2024-12-26 14:31:58

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

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

It will make more sense when you consider what operations the base 'Entity' class tries to perform. I'm also not familiar with nhibernate, but I would imagine one of the methods might be something akin to a Save() method. So any class you create that inherits from the Entity class would inherit a Save() method, keeping you from having to rewrite it for every business object you make. However, the Base entity class has to know what type of object you are trying to save. It could use reflection, but here it uses generics to allow you to tell it what kind of class it is that is inheriting Entity.

The thing is that when 20 different classes inherit from a base class, that base class doesn't really have any knowledge of who is using its functionality. This is a way to let the base class know "Customer" is using its methods so that it can cater specifically to "Customer"'s needs.

淡淡の花香 2024-12-26 14:31:58

where 子句指定要T替换的类型必须遵守的条件。因此,如果类型为 Customer(如第二行代码中的 Entity 所示),则条件为 Customer : Entity code> ... 即 Customer 必须是 Entity 的子类,否则会出现编译错误。事实上,在第二行代码中也是如此声明的。

将其应用到您所写的内容中:

此“Entity”将“Customer”作为 T

下面是我的说法:EntityEntity< 的实例化/code> 用 Customer 替换 TT 只是某种类型的占位符;它是一个类型参数

但该客户不是“Entity

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

如果您了解 T 只是一个参数,并且在 Entity的情况下用 Customer 代替它< /code>,那么我不明白为什么你说“这个客户不是“Entity””,因为 Customer : Entity 声明了它到就是这样(在 Entity 定义中每次出现时用 Customer 替换 T)。

The where clause specifies a condition that the type to be substituted for T must obey. So, if the type is Customer, as in Entity<Customer> in that second line of code, then the condition is Customer : Entity<Customer> ... i.e., Customer must be a subclass of Entity<Customer>, else there's a compile error. And indeed it is so declared, again in that second line of code.

Applying this to what you wrote:

this "Entity<Customer>" takes "Customer" as T

Here's how I would put it: Entity<Customer> is an instantiation of Entity<T> with Customer substituted for T. T is just a placeholder for some type; it's a type parameter.

but this customer is not "Entity<T>"

We could just as well write the abstract method declaration with SomeType instead of T. The condition is that, in order to instantiate Entity<SomeType>, SomeType must be a subclass of Entity<SomeType>. Substituting Customer for SomeType, that says that Customer must be a subclass of Entity<Customer>, and it is.

If you understand that T is just a parameter, and that Customer is substituted for it in the case of Entity<Customer>, then I don't understand why you say that 'this customer is not "Entity<T>"', since Customer : Entity<Customer> declares it to be just that (with Customer substituted for T in every occurrence in the definition of Entity<T>).

葬花如无物 2024-12-26 14:31:58

显示如何使用此类继承的示例:

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

Sample showing how one can use such inheritance:

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();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文