通用基础,协方差

Generic Bases, Covarience

我有一个通用基础 class,其他通用 class 继承自该基础:

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>

我做错了什么?

The two this give the error "cannot convert from B<T> to T. I understand that this is due to the fact that this could be something other that T (covariance) and therefore won't go into a List<T>.

我觉得你没看懂。

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

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

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

其次,你不明白"covariance"这个词是什么意思。我不知道你认为这意味着什么,但我猜你认为 "covariance" 意味着 "assignment compatibility"。这通常是人们认为 "covariance" 的意思,但他们的意思是错误的。

"Assignment compatibility" 是 属性 类型 Apple 的值可以进入类型 Fruit 的变量,因为 AppleFruit 的存储兼容的分配那不是协方差

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

即:Apple 可以进入 Fruit 类型的变量,因此 IEnumerable<Apple> 可以进入 IEnumerable<Fruit> 类型的变量。分配兼容性 的关系被保留,因为类型通过使它们通用 而变化,因此 IEnumerable<T>co-variant;事物朝着同一个方向变化

If I state that T inherits from B<T> there is no error for the first this but the error for the Add this remains.

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

Now surely if every T inherits from B<T>, then every B<T> is a T and therefore should go into a List<T>.

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

让我们再次让您的句子不那么混乱。我们将 T 替换为 Apple,将 B<T> 替换为 Fruit,我们有:

Now surely if every apple is a kind of fruit, then every fruit is an apple and therefore should go into a bowl of apples".

你的结论是苹果是水果,所以所有的水果都是苹果,所以你可以把一根香蕉放到一碗苹果里,它仍然是一碗苹果。说白了就是无稽之谈。

What am I doing wrong?

您构建的通用类型非常复杂,您无法正确理解它们。这意味着 使用 您的代码的人也无法理解它们。寻找更简单的方法来解决您的问题。