【问题标题】:C# .NET 4.0 and GenericsC# .NET 4.0 和泛型
【发布时间】:2011-02-06 09:40:30
【问题描述】:

我想知道是否有人可以告诉我这种行为在 C# 4.0 中是否可行

我有一个我想保持强类型的对象层次结构。像这样的

class ItemBase {}

class ItemType<T> where T : ItemBase 
{
   T Base { get; set; }
}


class EquipmentBase : ItemBase {}
class EquipmentType : ItemType<EquipmentBase> {}

我想要做这样的事情

ItemType item = new EquipmentType();

我希望 item.Base 返回类型 ItemBase。基本上我想知道它是否足够聪明,可以在没有强类型的情况下对基类进行强类型泛型。这样做的好处是我可以简单地将 ItemType 转换回 EquipmentType 并再次获得所有强类型。

我可能想错了……

【问题讨论】:

    标签: c# generics .net-4.0 polymorphism type-conversion


    【解决方案1】:

    不,因为就编译器而言,ItemType 是与ItemType&lt;EquipmentBase&gt;ItemType&lt;Foo&gt; 不同的类型。这三个都被视为唯一类型,它们不能相互代表。

    在您的类声明中,您将其声明为ItemType&lt;T&gt;,因此ItemType 将是无法编译的未定义类型。

    您最多可以使用ItemType&lt;EquipmentBase&gt; 对象来表示EquipmentType 或任何其他派生自ItemType&lt;EquipmentBase&gt; 的类,但不能使用ItemType&lt;PersonType&gt;

    【讨论】:

    • 由于我在回答中提到的两个原因,这在 C# 4 中也不起作用。但即使 ItemType 改为 IItemType,它需要 T 作为输入和输出参数这一事实有效地排除了所需的用法。
    【解决方案2】:

    你说的是协方差,它可以让你这样做:

    ItemType<object> item = new EquipmentType();
    

    由于以下原因,您无法在 C# 4 中执行此操作:

    1. 泛型协变仅适用于接口、数组和委托类型,不适用于基类
    2. 您的 ItemType 类使用 T 作为输入/输出类型参数,这意味着它接收一个 T 并返回一个 T。

    第 2 个问题是主要问题,因为如果允许,则以下代码必须是可编译的,但在运行时会失败。

    // this will not work
    ItemType<object> item = new EquipmentType();
    item.Base = new Object(); // this seems ok but clearly isn't allowed
    

    Covariance and Contravariance FAQ

    【讨论】:

      【解决方案3】:

      我认为 C# 4.0 的新特性不会对您有所帮助。但是,自从引入泛型以来,有一种解决方法已经有效:您创建一个与泛型类同名的抽象基类,并放置所有您想要且不需要接受或返回参数的成员泛型类型,如下所示:

      class ItemBase {
      }
      
      abstract class ItemType {
          public ItemBase Base {
              get { return GetItemBase(); }
              set { SetItemBase(value); }
          }
      
          protected abstract void SetItemBase(ItemBase value);
      
          protected abstract ItemBase GetItemBase();
      }
      
      class ItemType<T> : ItemType where T : ItemBase {
          protected override sealed void SetItemBase(ItemBase value) {
              Base = (T) value;
          }
      
          protected override sealed ItemBase GetItemBase() {
              return Base;
          }
      
          public new T Base { get; set; }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-07
        • 2011-08-16
        • 1970-01-01
        • 2011-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多