首页 > 解决方案 > 通用基础,协方差

问题描述

我有一个通用基类,其他通用类从该基类继承:

public class B<T> {

    private List<T> parent;

    public bool IsInParent() { return parent.Contains(this); }

    public void Attach() { parent.Add(this); }

}

两者this给出了错误“无法从转换B<T>T。我知道这是因为它this可能是 T (协方差)以外的东西,因此不会进入List<T>。我明白这一点。

如果我声明T继承自B<T>第一个没有错误,this但 Add 的错误this仍然存​​在。

public class B<T> where T : B<T> { ..... ]

现在可以肯定的是,如果Teach 继承自B<T>,那么 eachB<T>就是 a T,因此应该进入 a List<T>

我究竟做错了什么?

标签: c#listgenericsaddcovariance

解决方案


这两个给出了错误“无法转换B<T>T.thisTList<T>

我不认为你理解它。

第一:this是类型B<T>B<T>想象一下,我们把它变得更具体,而不是抽象:

class Comparer<T> // I can compare two things of type T.
{
    ....

thisinsideComparer<T>将是 type Comparer<T>。如果您有 a List<T>,则可以将 aT放入列表中。假设TApplethis可以比较两个苹果。List<T>可以包含两个苹果。但是List<T> 不能包含两个苹果比较器,因为那不是它的类型!

其次,你不明白“协方差”这个词是什么意思。我不知道您认为这意味着什么,但我的猜测是您认为“协方差”意味着“分配兼容性”。这通常是人们认为“协方差”的意思,当他们对它的含义有误时。

“赋值兼容性”是 type 的值Apple可以进入 type 的变量的属性Fruit,因为 anApple是与存储兼容的赋值Fruit那不是协方差

协变是泛型类型保留赋值兼容性关系的属性。

也就是说: an Applecan 进入 type 的变量Fruit,因此 an IEnumerable<Apple>can 进入 type 的变量IEnumerable<Fruit>。分配兼容性的关系被保留,因为类型通过使它们泛型而变化,因此IEnumerable<T>协变的;事物朝着同一个方向变化

如果我声明T继承自B<T>第一个 this 没有错误,但Add this剩下的错误。

首先:不要这样做。这是一个糟糕的模式。它是 C++ 模式的一种变体,称为“奇怪重复的模板模式”。我已经看到它在 C# 中使用了很多次,而且几乎总是用错了。躲开它。它使您的类型变得复杂、难以使用、难以理解,并且使您认为您对您的类型有一个 C# 不支持的约束。

现在可以肯定的是,如果Teach 继承自B<T>,那么 eachB<T>就是 a T,因此应该进入 a List<T>

现在你也许开始明白为什么这种模式如此糟糕了。它让你相信完全疯狂的虚假事物,因为它是如此令人困惑!

让我们再次让你的句子不那么混乱。我们将替换TAppleB<T>并且Fruit我们有:

现在可以肯定,如果每个苹果都是一种水果,那么每个水果都是一个苹果,因此应该放入一碗苹果中”。

你的结论是苹果是水果,因此所有的水果都是苹果,所以你可以把一根香蕉放进一碗苹果里,它仍然是一碗苹果。显然,这是荒谬的。

我究竟做错了什么?

您正在构建的泛型类型非常复杂,以至于您无法正确理解它们。这意味着使用您的代码的人也将无法理解它们。找到一种更简单的方法来解决您的问题。


推荐阅读