简体   繁体   English

在 LINQ 表达式中不使用 IComparer

[英]IComparer is not used in LINQ expressions

I'm seeing some weird behavior and not able to figure out how it can occur.我看到一些奇怪的行为,无法弄清楚它是如何发生的。 I have 2 sorted sets which I am using a buffers to reorder TCP packets by sequence number, and I am reading packets out of these sets within a lock statement.我有 2 个排序集,我正在使用缓冲区按序列号对 TCP 数据包重新排序,并且我正在锁定语句中从这些集合中读取数据包。

Here is a simplified example:这是一个简化的示例:

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;
            ...
        }
    }
}

And something is causing this exception:有些东西导致了这个异常:

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)

which seems to imply that after checking Count > 0 , Min() found no objects.这似乎意味着在检查Count > 0之后, Min()没有发现任何对象。 I am very confused as to how this could happen while locked.我对锁定时如何发生这种情况感到非常困惑。

This is answer extracted from comments below the question这是从问题下方的评论中提取的答案

This is not a lock related issue.不是与锁相关的问题。

As per the comments, OP implemented IComparer<Packet> and passed it into SortedSet<Packet> .根据评论,OP 实现了IComparer<Packet>并将其传递给SortedSet<Packet> The comparer whilst it is used by the collection, Min method being a LINQ extension does not use it.集合使用的比较器,作为 LINQ 扩展的Min方法不使用它。

Instead, Min expects the Packet class to implement IComparable .相反, Min期望Packet class 实现IComparable And because the class does not seem to have implemented the interface, the exception is thrown.并且因为class好像没有实现接口,所以抛出异常。

Min does not compare objects when collection only contains 0 or 1 items.当集合仅包含 0 或 1 个项目时, Min不比较对象。 When the collection contains 2 or more items, Min compares Packet and the exception is thrown.当集合包含 2 个或更多项时, Min比较Packet并抛出异常。

As per the OP's comment, this is where the confusion was:根据 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. )大多数时候,缓冲区中只有 1 个数据包(除了极少数情况下的乱序数据包,这是我试图用这个缓冲区解决的问题。)

The error message however might also be misleading in this scenario:然而,在这种情况下,错误消息也可能具有误导性:

At least one object must implement IComparable.至少一个 object 必须实现 IComparable。

It implies there might be no items in the set.这意味着集合中可能没有项目。

To fix this issue, because the sets are already ordered, using First or Last as per the implementation of IComparer<Packet> should work.要解决此问题,因为集合已经排序,根据IComparer<Packet>的实现使用FirstLast应该可以工作。

Instead of using the Enumerable.Min extension method of the LINQ library, use the SortedSet.Min property instead:不要使用 LINQ 库的Enumerable.Min扩展方法,而是使用SortedSet.Min属性:

Gets the minimum value in the SortedSet<T> , as defined by the comparer.获取由比较器定义的SortedSet<T>中的最小值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM