此 LINQ 表达式枚举是否不安全,因为它修改了表达式中的一个对象

本文关键字:表达式 修改 一个对象 枚举 LINQ 是否 不安全 因为 | 更新日期: 2023-09-27 18:36:49

在我的代码中,我有三个列表。

  1. 我排队等待创建/检索的项目列表(已请求)
  2. 我当前正在构建(工作)的项目列表
  3. 上次请求中缺少的项目列表。这可能包括我已经请求并正在检索的项目的副本。(缺失)

我只想对尚未排队或正在处理的请求的项目进行排队,我想到了以下 LINQ 表达式......

// Queue object requests if they aren't already requested
foreach (int id in missing.Except(requested.Concat(working)))
    requested.Enqueue(id);

但是,假设 Except 正在使用延迟执行,我可能在枚举列表时修改列表,这通常会引发异常或导致问题,这里出现了危险信号。

当然,我可以在不使用 LINQ 和/或单独检查每个列表然后添加它的情况下重写它,但问题仍然存在。为什么或为什么这不起作用?我认为它可能会引发异常,所以我编写了以下测试:

private void Test()
    {
        Queue<int> missing   = new Queue<int>();
        Queue<int> requested = new Queue<int>();
        Queue<int> working   = new Queue<int>();
        missing.Enqueue(5);  // also in working
        missing.Enqueue(10);
        missing.Enqueue(67);
        missing.Enqueue(96); // also in requested
        requested.Enqueue(47);
        requested.Enqueue(66);
        requested.Enqueue(84);
        requested.Enqueue(89);
        requested.Enqueue(96);
        working.Enqueue(1);
        working.Enqueue(5);
        working.Enqueue(33);
        foreach (int i in missing.Except(requested.Concat(working)))
            requested.Enqueue(i);
    }

此代码有效并返回预期结果(请求现在包含 7 项,包括 10 和 67)。我认为这可能会引发异常..那么,是我错了,这很好,还是我说这会引起问题?

(显然问题不在于如何使其工作,因为我知道我可以先检查请求,但我想了解这个 LINQ 表达式的工作原理)

此 LINQ 表达式枚举是否不安全,因为它修改了表达式中的一个对象

由于将一个集合的所有元素与另一个集合的所有元素进行比较的潜在 O(n^2) Except 在内部使用哈希集通过其哈希代码对集合项进行分区,然后仅比较每个存储桶中的项。

这样做的结果是,Except 实际上不是一个惰性的 LINQ 运算符,并且在您读出第一项时会完全计算。