【问题标题】:Casting generic classes in C#在 C# 中强制转换泛型类
【发布时间】:2013-01-23 08:58:29
【问题描述】:

我在转换泛型类型时遇到问题。

例如我有课:

public class Dog
{
}

public class Husky : Dog
{

}

public class MyWrapper<T> where T : class
{
}

然后我想做这样的事情,但我不知道怎么做

MyWrapper<Husky> husky = new MyWrapper<Husky>();
List<MyWrapper<Dog>> dogs= new List<MyWrapper<Dog>>();
dogs.Add(husky); // how to cast husky to MyWrapper<Dog>?

编辑:将 Animal&lt;T&gt; 更改为 MyWrapper&lt;T&gt;,所以这将是更充分的示例

【问题讨论】:

    标签: c# generics casting


    【解决方案1】:

    您可以在 C# 4 或更高版本中使用接口的generic covariance。为此,您需要定义一个协变接口(使用out)并让MyWrapper 实现该接口:

    public class Dog 
    {
    }
    
    public class Husky : Dog
    {
    }
    
    public class MyWrapper<T> : IMyWrapper<T> where T : class
    {
    }
    
    public interface IMyWrapper<out T> where T : class
    {
    }
    

    那么你可以这样做:

    var husky = new MyWrapper<Husky>();
    var dogs = new List<IMyWrapper<Dog>>();
    dogs.Add(husky);
    

    【讨论】:

      【解决方案2】:

      恐怕你不能——尽管HuskyDogAnimal&lt;Husky&gt; 不是Animal&lt;Dog&gt;

      请参阅.NET Casting Generic List 了解类似问题。

      【讨论】:

      • +1。通常,泛型从它们的泛型类型继承,就是这样 - 参数的层次结构没有保留。这也是有道理的,因为它可能并不总是可以这样做(使用多个参数)。
      【解决方案3】:

      您为什么不按如下方式安排您的类继承?我不确定为什么 Animal 需要接受类型参数。

      public abstract class Animal
      {
      }
      
      public class Dog : Animal
      {
      }
      
      public class Husky : Dog 
      {
      }
      

      【讨论】:

      • 同意,虽然我只能说 - 他做了一个不错的例子,因此它应该站得住脚。如果这将是一个真正的类层次结构,那么它就是滥用泛型而不是简单的继承,正如您所指出的那样。
      【解决方案4】:

      为此,您需要 协方差 - 向上转换一个泛型类型 -.

      但 C# 协方差仅支持:

      • 代表。
      • 接口。

      为此,我只找到了一个解决方案:创建标记界面IAnimal&lt;T&gt;

      public class Dog
      {
      }
      
      public class Husky : Dog
      {
      
      }
      
      public interface IAnimal<out T>
          where T : class
      {
      }
      
      public class Animal<T> : IAnimal<T> where T : class
      {
      }
      

      现在这将起作用:

              List<IAnimal<Dog>> list = new List<IAnimal<Dog>>();
              list.Add(new Animal<Husky>());
      

      在 MSDN 上了解有关协变和逆变的更多信息:

      更新

      无论如何...通用约束T : class 的意义何在?你只知道T 是一个类,但它可能没有公共构造函数,或者它可能是一块石头而不是一条狗,谁知道呢?

      或者,这个类层次结构的意义何在?正如其他人在他们的回答中指出的那样,您的层次结构不是非常面向对象的:狗 是动物 所以Dog DERIVES Animal

      只要改变它,你就不再需要使用泛型类型参数了。

      也许你更喜欢组合而不是继承,但我倾向于用这个问题来决定什么是最好的:

      • 如果我说专业类型,我可以说“B is A”吗? => 那我选择继承

      • 如果我说特化类型,我能说“B 是 A 的一部分”吗 => 那我选择组合

      其实我相信协方差可以解决你的问题,但我觉得这是这个语言特性的错误用例。

      【讨论】:

      • 它有效,谢谢!在我的项目中,有类似class Wrapper&lt;T&gt; 的东西,所以它不会被 T 类型的类继承。抱歉,我的 Animal 示例很不幸。不过还是感谢您解决了我的问题。
      • @vanilla161 是的,我认为(关于包装器的事情),但我必须回答你的实际问题文本:(
      【解决方案5】:

      不可能Animal&lt;Husky&gt; 不是从Animal&lt;Dog&gt; 派生的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-02-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多