我有一个继承其他泛型类的泛型基类:
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>
。
我在做什么错了?
答案 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
放入列表中。假设T
是Apple
。 this
可以比较两个苹果。 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
,我们得到:
现在肯定如果每个苹果都是一种水果,那么每个水果都是一个苹果,因此应该放入一碗苹果。”
您的结论是苹果是水果,因此所有水果都是苹果,因此您可以将香蕉放入一碗苹果中,而它仍然是一碗苹果。显然,这是荒谬的。
我在做什么错了?
您正在构建的泛型类型非常复杂,以至于您无法正确理解它们。这意味着使用代码的人也将无法理解他们。找到一种更简单的方法来解决您的问题。