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> 的实施使用 FirstLast 应该可以。

而不是使用 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.