Jef*_*nes 11 c# generics inheritance covariance
这样做的目的是同步包含图形边缘的两个集合,发送方和接收方,以便在发生某些事情时(删除边缘,添加边缘等)通知双方.
为此,对集合的(反向)引用包含在集合中的元素中
class EdgeBase {
EdgeBase(ICollection<EdgeBase> rCol, ICollection<EdgeBase> sCol)
{ RecvCol=rCol; SendCol=sCol; }
ICollection<EdgeBase> RecvCol;
ICollection<EdgeBase> SendCol;
public virtual void Disconnect() // Synchronized deletion
{ RecvCol.Remove(this); SendCol.Remove(this); }
}
class Edge : EdgeBase {
Edge(ICollection<EdgeBase> rCol, ICollection<EdgeBase> sCol)
: base(rCol, sCol) {}
int Weight;
}
Run Code Online (Sandbox Code Playgroud)
删除(断开连接)没问题,但在创建过程中出现了问题:
HashSet<Edge> receiverSet, senderSet;
var edge = new Edge(receiverSet, senderSet); // Can't convert Edge to EdgeBase!
Run Code Online (Sandbox Code Playgroud)
虽然Edge是源于EdgeBase此,但这是非法的.(问题是Edge一部分,而不是HashSet<>一部分.)
在写完数百行之后,我发现ICollection<>它并不是协变的IEnumerable<>.
什么是解决方法?
编辑:
如果我在不破坏C#的协方差规则的情况下编写上面的代码,那就像这样:
public class EdgeBase<T, U>
where T : ICollection<U<T>> // illegal
where U : EdgeBase<T, U> // legal, but introduces self-reference
{
public EdgeBase(T recvCol, T sendCol) {...}
protected T ReceiverCollection;
protected T SenderCollection;
public virtual void Disconnect() {...}
}
Run Code Online (Sandbox Code Playgroud)
但这是非法的; 'U'不能与形式参数T一起使用.
aia*_*tag 17
Eric Lippert说C#只支持类型安全的协方差和逆变.如果你想到它,制作ICollection协变不是类型安全的.
让我们说你有
ICollection<Dog> dogList = new List<Dog>();
ICollection<Mammal> mammalList = dogList; //illegal but for the sake of showing, do it
mammalList.Add(new Cat());
Run Code Online (Sandbox Code Playgroud)
你的mammalList(实际上是一个dogList)现在将包含一个Cat.
IEnumerable<T>是协变的,因为你不能Add这样......你只能从中读取 - 这反过来又保留了类型安全性.
| 归档时间: |
|
| 查看次数: |
2161 次 |
| 最近记录: |