【问题标题】:C# Generic Polymorphism [duplicate]C#泛型多态[重复]
【发布时间】:2018-06-07 16:27:36
【问题描述】:

假设有一个像这样的基类,称为Cup

public abstract class Cup { }

我们假设有PaperCup 继承CupPlasticCup 继承PaperCup 类。

public class PlasticCup : PaperCup { }
public class PaperCup : Cup { }

并假设 Main 类中有两个方法。

static void Test01 (PaperCup cup) { }
static void Test02 (Cup cup) { }

测试1

PaperCup A = new PaperCup();
Test01(A);
Test02(A);

上面的代码工作正常。 A 实例可以传递给这两个函数,因为它本身就是 PaperCup 并且它继承了 Cup 基类。

测试2

PlasticCup B = new PlasticCup();
Test01(B);
Test02(B);

上面的代码仍然可以正常工作。 B 实例虽然是PlasticCup,但也可以被函数获取,但它继承PaperCup,最终派生自Cup

但是泛型!!

让我们看看下面的方法。

static void Test010 (IList<PaperCup> cup) { }
static void Test011(IList<PlasticCup> cup) { }
static void Test012(IList<Cup> cup) { }

下面的这个试验将在两次方法调用中失败。

IList<PlasticCup> BB = new List<PlasticCup>();
Test010(BB); // Fail CS1503 Compiler Error
Test011(BB);
Test012(BB); // Fail CS1503 Compiler Error

简单问题

为什么当它们采用Generic 时,无法将派生类型传递给这些函数?因为 C# 是一种 OOP 语言,它不应该工作吗?

【问题讨论】:

  • “因为 C# 是一种 OOP 语言?”我想知道你是怎么得出这个结论的。 C# 是一种多范式语言,甚至是一种函数式语言。
  • @CamiloTerevinto imo 这不是一个很好的更新,如果您要编辑,更改代码几乎不是一个好主意。
  • @DavidG 怎么样?我只删除了完全不相关的代码,使问题更短。
  • @CamiloTerevinto 只需对问题进行很小的更改,该代码就会变得相关。该代码没有造成任何伤害,删除它是一种浪费。

标签: c# oop generics polymorphism


【解决方案1】:

好的,想象一下以下是允许的:

IList<Cup> plasticCups = new List<PlasticCup>();

那么以下是可能的:

plasticCups.Add(new PaperCup()); //ouch!

您刚刚在塑料杯列表中插入了一个纸杯。这似乎不对。

你问的是generic type varianceIList&lt;T&gt;T 中是不变的,因为任何其他选项(协变或逆变)都是不安全的

C#确实允许接口和委托中的泛型类型变化,但前提是编译器可以确保其安全。

例如,IEnumerable&lt;out T&gt;T 中是协变的,因为您不能将纸杯插入IEnumerable&lt;PlasticCup&gt;(规则实际上是T 类型永远不会用作方法参数),所以以下是完全安全的,可以编译:

IEnumerable<Cup> plasticCups = Enumerable.Empty<PlasticCup>();

有趣的是,由于在 C# 诞生时“支持其他现有语言特性”的原因,数组也支持类型变化,但它完全被破坏了。对于数组,这是完全合法的:

object[] strings = new string[] { .... }
strings[0] = new object(); //oh oh

你会得到一个不幸的运行时异常。使用泛型就不会发生这种情况。

【讨论】:

  • 次要点:这不是关于“插入”T 到泛型类型中,而是关于将类型作为输入的泛型类型。所以是的,这可能是 Add 方法,但也可能是其他任何方法。
  • @DavidG 好点!添加只是一个明显的例子,但是是的,Find(T t) 同样不安全。
  • 这也是一个骗局,但我正在尝试找出最佳目标! :)
猜你喜欢
  • 2017-05-14
  • 2012-01-20
  • 2019-06-04
  • 2011-08-23
  • 2018-01-19
  • 2010-09-26
  • 1970-01-01
  • 1970-01-01
  • 2021-07-17
相关资源
最近更新 更多