如果lock()中的延迟LINQ语句发出编译警告

本文关键字:语句 编译 警告 LINQ 延迟 lock 如果 | 更新日期: 2023-09-27 18:19:59

如果未执行的LINQ语句在锁内,Visual Studio是否应该发出警告?问题是返回IEnumerables的LINQ语句被推迟,因此当读取LINQ结果时,它们可以在锁定之后执行。

以下代码再现了集合被修改异常的场景:

private static readonly List<KeyValuePair<string, double>> list = new List<KeyValuePair<string, double>>()
  {
      new KeyValuePair<string, double>("A", 0),
      new KeyValuePair<string, double>("B", 1),
      new KeyValuePair<string, double>("C", 2)
  };
  static void Main(string[] args)
  {
      new Timer(Write, null, 0, 1);
      new Timer(Read, null, 0, 1);
      Thread.Sleep(Timeout.Infinite);
  }
  private static void Write(object state)
  {
      lock (list)
      {
          for (int i = 0; i < list.Count; i++)
          {
              list[i] = new KeyValuePair<string, double>(list[i].Key, list[i].Value + 1);
          }
      }
  }
  private static void Read(object state)
  {
      IEnumerable<string> tempList;
      lock (list)
      {
          tempList = list.Select(it => it.Key + ":" + it.Value); // LINQ not always executed here
      }
      foreach (var s in tempList) // may trigger an Exception: Collection was modified
      {
          Console.WriteLine(s);
      }
  }

如果lock()中的延迟LINQ语句发出编译警告

否。

  1. 编译器不一定知道是否可以在lock语句的范围之外执行查询。这将取决于它使用的具体启发式方法,但假阳性和假阴性的几率可能很大。

  2. lock语句之外公开LINQ查询并不一定是错误的。通常是这样,但不是普遍如此。

    例如,即使在您给出的例子中,如果您的Write函数用新的List替换list,而不是对其进行更改,那么*您的代码将是安全的,并且可以正常工作。让作为根数据源的LINQ查询是不可变的(或者任何其他类型的IEnumerable<T>,可以在关键部分之外安全地迭代,其中有很多)是一种安全的操作。

  3. 这不是一个非常常见的问题,很大一部分开发人员可能会遇到这个问题。

这充其量是第三方代码分析工具中的一个警告(即使在那里,由于给定的原因,它也可能无法成功)。它肯定不会出现在编译器的警告套件中。