【问题标题】:Substituting implementations into the T of a parameterized class of type T将实现替换为 T 类型的参数化类的 T
【发布时间】:2018-10-27 01:24:49
【问题描述】:

假设我有一个类似的设置

public interface IMyInterface { }

public class MyImplementation : IMyInterface { }

public class MyClass<T> where T : IMyInterface { }

我发现我不能像这样替换

var list = new List<MyClass<IMyInterface>>()
{
   new MyClass<MyImplementation>()
}

因为我会得到错误

无法从 MyClass&lt;MyImplementation&gt; 转换为 MyClass&lt;IMyInterface&gt;

这是否意味着我正在尝试做的是代码异味?

【问题讨论】:

  • 这是一个编译器错误,因此这意味着您尝试执行的操作在 c# 语言中是非法的。
  • 您不能这样做,因为List&lt;T&gt; 中的T 是不变的。换句话说,它必须是一种类型(它不能变化)。谷歌协变和逆变。这个问题在 SO 上也被问了太多次了。
  • 我认为您要研究的是 C# 中的泛型方差,两个关键术语是协方差和反方差。我不会给出答案,因为它可能无法很好地涵盖它,因为它仍然让我头疼,所以我的建议是查找这些术语,直到更有知识的人可以给你一个好的答案跨度>

标签: c# .net oop


【解决方案1】:

它不允许这样做,因为List&lt;T&gt; 中的T 是不变的。这是一个解释的例子:

public interface IFruit
{
    string Name { get; set; }
}

public class Apple : IFruit
{
    public string Name { get; set; }
    public string Color { get; set; }
}

public class Orange : IFruit
{
    public string Name { get; set; }
}

让我们在列表中添加一些水果:

var fruits = new List<IFruit>();
fruits.Add(new Apple());
fruits.Add(new Orange());

在代码的后面,你不知道添加了什么,你这样做:

Orange orange = fruits[0];

现在这不会编译,但它也没有意义,因为每个IFruit 都不是AppleOrange

如果编译器允许怎么办?

例如,假设您正在尝试的内容是编译器允许的,如下所示:

// does not compile but let's say it did
List<Apple> fruits = new List<IFruit>(); 

如果编译器允许这样做,它也应该允许这样做,因为它们都实现了IFruit

fruits.Add(new Apple());
fruits.Add(new Orange());

然后稍后在代码中的某个地方执行此操作(因为它是一个苹果列表):

foreach (var thisFruit in fruits)
{
    Console.WriteLine(thisFruit.Color)
}

崩溃!!编译器一开始并没有阻止您,此时您正在查看代码,它显示List&lt;Apple&gt;,您编写了代码并全部编译。在运行时,哦,废话,没有Color 属性,因为它是Orange

这就是不允许的原因。

【讨论】:

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