【问题标题】:Need help to understand this C# generic class需要帮助来理解这个 C# 泛型类
【发布时间】:2011-12-06 02:31:00
【问题描述】:

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

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

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

public class Customer : Entity<Customer>

我知道它是一个抽象的泛型类,它使用where 关键字来确保T 的类型是Entity&lt;T&gt;,这就是我感到困惑的地方。

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

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

【问题讨论】:

  • 如果该示例在网络上某处,您能否提供一个指向您的实际示例的链接?我已经搜索过,但我找不到它。我自己也有这个问题。干杯。

标签: c# nhibernate generics generic-constraints


【解决方案1】:

你说

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

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

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

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

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

比如说它有一个名为

的方法
public IEnumerable<T> GetEntities() 

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

public IEnumerable<Customer> GetEntities<Customer>() 

如果没有泛型参数,则只能返回IEnumerable&lt;Entity&gt;

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

【讨论】:

  • 对不起,这没有任何意义,因为我真的很困惑,并尝试了解它是如何工作的。你能纠正我说的更有意义吗?
  • @feelexit 你说“Customer 不是Entity&lt;T&gt;”但它是。该类被声明为 public class Customer : Entity&lt;Customer&gt;,这意味着 Customer isEntity&lt;Customer&gt;
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    where 子句指定要替换T 的类型必须遵守的条件。所以,如果类型是Customer,就像第二行代码中的Entity&lt;Customer&gt;,那么条件是Customer : Entity&lt;Customer&gt; ...即Customer必须是Entity&lt;Customer&gt;的子类,否则会有编译错误。确实如此声明,再次在第二行代码中。

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

    此“Entity&lt;Customer&gt;”将“客户”作为 T

    我会这样说:Entity&lt;Customer&gt;Entity&lt;T&gt; 的实例化,Customer 替换了TT 只是某种类型的占位符;这是一个类型参数

    但此客户不是“Entity&lt;T&gt;

    我们也可以用 SomeType 代替T 来编写抽象方法声明。条件是,为了实例化Entity&lt;SomeType&gt;SomeType 必须是Entity&lt;SomeType@987654339 的子类@。将Customer 替换为SomeType,这表示Customer 必须是Entity&lt;Customer&gt; 的子类,并且确实如此。

    如果你明白T 只是一个参数,而CustomerEntity&lt;Customer&gt; 的情况下被替换,那么我不明白你为什么说'此客户不是“Entity&lt;T&gt;”,因为Customer : Entity&lt;Customer&gt; 声明它就是这样(CustomerEntity&lt;T&gt; 的定义中的每次出现都替换了T)。

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-20
        • 1970-01-01
        • 2016-02-10
        • 2011-05-04
        • 1970-01-01
        • 2019-08-11
        • 2020-08-06
        • 1970-01-01
        相关资源
        最近更新 更多