通用基数,协方差

时间:2018-08-24 00:57:20

标签: c# list generics add covariance

我有一个继承其他泛型类的泛型基类:

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没有错误,但添加this的错误仍然存​​在。

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

现在,如果每个T都继承自B<T>,那么每个B<T>就是一个T,因此应该放入一个List<T>

我在做什么错了?

1 个答案:

答案 0 :(得分:7)

  

这两个产生错误“无法从B<T>转换为T。我了解这是由于this可能是T以外的其他事实(协方差),因此不会进入List<T>

我认为您听不懂。

首先:this的类型为B<T>。想象一下,而不是抽象的B<T>,我们将其变得更加具体:

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

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

第二,您不理解“协方差”一词的含义。我不知道您的意思,但是我猜您认为“协方差”意味着“分配兼容性”。这就是人们通常认为“协方差”在含义错误时的意思。

“分配兼容性”是一种属性,类型Apple的值可以进入类型Fruit的变量中,因为Apple分配兼容Fruit的存储空间。 那不是协方差

协方差是通过通用类型保留分配兼容性关系的属性。

也就是说:Apple可以进入类型Fruit的变量,因此IEnumerable<Apple>可以进入类型IEnumerable<Fruit>的变量。分配兼容性的关系随着类型的变化而保持不变,因此得以保留,因此IEnumerable<T>协变;事物在同一方向上一起变化。

  

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

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

  

现在,如果每个T都继承自B<T>,那么每个B<T>就是一个T,因此应该放入一个List<T>

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

让我们再次减少您的句子的混乱。我们将T替换为Apple,将B<T>替换为Fruit,我们得到:

  

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

您的结论是苹果是水果,因此所有水果都是苹果,因此您可以将香蕉放入一碗苹果中,而它仍然是一碗苹果。显然,这是荒谬的。

  

我在做什么错了?

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