LINQ 表达式中不使用 IComparer
IComparer is not used in LINQ expressions
我看到了一些奇怪的行为,但无法弄清楚它是如何发生的。我有 2 个排序集,我正在使用缓冲区按序列号重新排序 TCP 数据包,并且我正在 lock 语句中从这些集中读取数据包。
这是一个简化的例子:
SortedSet<Packet> in = new SortedSet<TcpPacket>(new SeqComparer()); // inbound buffer
SortedSet<Packet> out = new SortedSet<TcpPacket>(new SeqComparer()); // outbound buffer
public void BufferPacket(Packet packet) {
// Some code which does not modify buffers
bool buffer = isOutbound ? out : in;
lock (buffer) {
buffer.Add(packet);
Packet bufferedPacket;
// Removing retransmitted packets
while (buffer.Count > 0 && (bufferedPacket = buffer.Min()).SeqNum < expected) {
buffer.Remove(bufferedPacket);
}
// Process buffer
while (buffer.Count > 0 && (bufferedPacket = buffer.Min()).SeqNum == expected) {
buffer.Remove(bufferedPacket);
expected += bufferedPacket.Length;
...
}
}
}
有些东西导致了这个异常:
System.ArgumentException: At least one object must implement IComparable.
at System.Collections.Comparer.Compare(Object a, Object b)
at System.Linq.Enumerable.Min[TSource](IEnumerable`1 source)
这似乎意味着在检查 Count > 0
之后,Min()
没有发现任何对象。我很困惑在锁定时怎么会发生这种情况。
这是从问题下方的评论中提取的答案
这是不是锁相关的问题。
根据评论,OP 实施了 IComparer<Packet>
并将其传递给 SortedSet<Packet>
。比较器虽然被集合使用,但作为 LINQ 扩展的 Min
方法不使用它。
相反,Min
期望 Packet
class 实现 IComparable
。又因为class好像没有实现接口,所以抛出异常。
Min
当集合仅包含 0 或 1 个项目时不比较对象。当集合包含 2 个或更多项时,Min
比较 Packet
并抛出异常。
根据 OP 的评论,这就是混淆所在:
Most of the time there is just 1 packet in the buffer (except for rare cases of out-of-order packets which is what I am trying to solve with this buffer. )
然而,在这种情况下,错误消息也可能具有误导性:
At least one object must implement IComparable.
这意味着集合中可能没有项目。
要解决此问题,因为集合已经订购,根据 IComparer<Packet>
的实施使用 First
或 Last
应该可以。
而不是使用 Enumerable.Min
extension method of the LINQ library, use the SortedSet.Min
属性 代替:
Gets the minimum value in the SortedSet<T>
, as defined by the comparer.
我看到了一些奇怪的行为,但无法弄清楚它是如何发生的。我有 2 个排序集,我正在使用缓冲区按序列号重新排序 TCP 数据包,并且我正在 lock 语句中从这些集中读取数据包。
这是一个简化的例子:
SortedSet<Packet> in = new SortedSet<TcpPacket>(new SeqComparer()); // inbound buffer
SortedSet<Packet> out = new SortedSet<TcpPacket>(new SeqComparer()); // outbound buffer
public void BufferPacket(Packet packet) {
// Some code which does not modify buffers
bool buffer = isOutbound ? out : in;
lock (buffer) {
buffer.Add(packet);
Packet bufferedPacket;
// Removing retransmitted packets
while (buffer.Count > 0 && (bufferedPacket = buffer.Min()).SeqNum < expected) {
buffer.Remove(bufferedPacket);
}
// Process buffer
while (buffer.Count > 0 && (bufferedPacket = buffer.Min()).SeqNum == expected) {
buffer.Remove(bufferedPacket);
expected += bufferedPacket.Length;
...
}
}
}
有些东西导致了这个异常:
System.ArgumentException: At least one object must implement IComparable.
at System.Collections.Comparer.Compare(Object a, Object b)
at System.Linq.Enumerable.Min[TSource](IEnumerable`1 source)
这似乎意味着在检查 Count > 0
之后,Min()
没有发现任何对象。我很困惑在锁定时怎么会发生这种情况。
这是从问题下方的评论中提取的答案
这是不是锁相关的问题。
根据评论,OP 实施了 IComparer<Packet>
并将其传递给 SortedSet<Packet>
。比较器虽然被集合使用,但作为 LINQ 扩展的 Min
方法不使用它。
相反,Min
期望 Packet
class 实现 IComparable
。又因为class好像没有实现接口,所以抛出异常。
Min
当集合仅包含 0 或 1 个项目时不比较对象。当集合包含 2 个或更多项时,Min
比较 Packet
并抛出异常。
根据 OP 的评论,这就是混淆所在:
Most of the time there is just 1 packet in the buffer (except for rare cases of out-of-order packets which is what I am trying to solve with this buffer. )
然而,在这种情况下,错误消息也可能具有误导性:
At least one object must implement IComparable.
这意味着集合中可能没有项目。
要解决此问题,因为集合已经订购,根据 IComparer<Packet>
的实施使用 First
或 Last
应该可以。
而不是使用 Enumerable.Min
extension method of the LINQ library, use the SortedSet.Min
属性 代替:
Gets the minimum value in the
SortedSet<T>
, as defined by the comparer.