【问题标题】:Generic Type conversion on type parameter inheritance类型参数继承上的泛型类型转换
【发布时间】:2012-11-29 00:51:24
【问题描述】:

给定以下代码:

namespace sample
{
    class a { }

    class b : a { }

    public class wrapper<T> { }

    class test
    {
        void test1()
        {
            wrapper<a> y = new wrapper<b>();
            //Error 11  Cannot implicitly convert type 'sample.wrapper<sample.b>' to 'sample.wrapper<sample.a>' 
        }
    }
}

从逻辑上讲,因为ba,所以wrapper&lt;b&gt;wrapper&lt;a&gt;。那为什么我不能进行这种转换,或者我该怎么做呢?

谢谢。

【问题讨论】:

标签: c#


【解决方案1】:

因为 b 是 a,所以 wrapper&lt;b&gt;wrapper&lt;a&gt;

嗯,对于 .NET 泛型类来说,情况并非如此,它们不能是协变的。 您可以使用接口协方差实现类似的功能:

class a { }
class b : a { }

public interface Iwrapper<out T> { }
public class wrapper<T> : Iwrapper<T> {}

class test
{
    void test1()
    {
        Iwrapper<a> y = new wrapper<b>();
    }
}

【讨论】:

  • 谢谢!我想这样就可以了!
【解决方案2】:

这是一个协方差问题。

b 类是 a,但 wrapper&lt;b&gt; 不是 wrapper&lt;a&gt;

您可以像这样使用 C# 4 的 covariance 语法来允许它:

public interface IWrapper<out T> { ... }

public class Wrapper<T> : IWrapper<T> { ... }

这将指示 CLR 将 Wrapper&lt;B&gt; 视为 Wrapper&lt;A&gt;

(作为记录:C# 有大写约定;类名是 Pascal 大小写的)。

【讨论】:

  • 不幸的是,协变仅与接口和委托有关。
  • 感谢您的帮助。我知道并使用约定,只是在这个项目中删除它们很方便,因为我使用反射在 javascript 中生成语句。
【解决方案3】:

让我们做一个场景。让我们调用类aMammal,类bDog,假设wrapper&lt;T&gt;类是List&lt;T&gt;

看看这段代码发生了什么

List<Dog> dogs = new List<Dog>();  //create a list of dogs
List<Mammal> mammals = dogs;   //reference it as a list of mammals

Cat tabby = new Cat();
mammals.Add(tabby)   // adds a cat to a list of dogs (!!?!)

Dog woofer = dogs.First(); //returns our tabby
woofer.Bark();  // and now we have a cat that speaks foreign languages

(我在How to store base class children in a dictionary? 上的回答转述)

【讨论】:

  • 我正在尝试做狗对哺乳动物,而不是哺乳动物对狗。我的问题是为什么不允许狗到哺乳动物!实际上,将 Cat 添加到 Mammals 列表中没有问题,因为 Mammals 不需要是 Dogs 的同一个实例。但是将哺乳动物变成狗或猫显然是不可能的。
  • 如果我们能够将dogs 转换为mammals,我们就可以将一只猫添加到列表中,并通过dogs 引用将其从集合中取出一只狗。我已经修改了示例,希望现在更清楚。
  • 在转换后,哺乳动物无需成为狗的同一个实例。例如,您可以将 String 转换为 Char[] 然后修改字符而不修改字符串。您可以将 DateTime 转换为 String,然后在不更改日期的情况下更改字符串。
  • 那些是值类型(或具有值类型语义)。使用引用时,狗和哺乳动物列表是完全相同的列表,只是引用了两次。如果您想将狗复制到哺乳动物列表中,C# 编译器对此非常满意。代码List&lt;Mammal&gt; mammals = new List&lt;Mammal&gt;(dogs); 按预期工作。
  • 事实上。使用数组而不是列表,您的示例将编译并运行,当您尝试将猫添加到哺乳动物时抛出异常。
猜你喜欢
  • 2015-11-18
  • 2018-09-27
  • 2015-09-15
  • 2018-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-19
相关资源
最近更新 更多