【发布时间】:2013-06-04 12:00:00
【问题描述】:
这样做的目的是同步两个集合,发送方和接收方,包含一个图边,以便在发生某些事情时(删除边、添加边等)通知双方。
为此,对集合的(反向)引用包含在集合中的元素中
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;
}
删除(断开)没问题,但创建过程中出现问题:
HashSet<Edge> receiverSet, senderSet;
var edge = new Edge(receiverSet, senderSet); // Can't convert Edge to EdgeBase!
虽然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() {...}
}
但这是非法的; 'U' 不能与形参 T 一起使用。
【问题讨论】:
-
receiverSet.Cast
() -
原因:question-about-c-sharp-covariance 您承认。解决方案:why-can-i-not-assign-a-list-of-concrete-types-to-a-list-of-that-concrete's-interface。第二部分在 SO 上经常被问到。
-
上面链接上的答案建议使用泛型方法,但它可以用于构造函数吗?
-
@JeffreyGoines 这是可能的。我会做一个通用的答案:)
标签: c# generics inheritance covariance