如果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
语句的范围之外执行查询。这将取决于它使用的具体启发式方法,但假阳性和假阴性的几率可能很大。 -
在
lock
语句之外公开LINQ
查询并不一定是错误的。通常是这样,但不是普遍如此。例如,即使在您给出的例子中,如果您的
Write
函数用新的List
替换list
,而不是对其进行更改,那么*您的代码将是安全的,并且可以正常工作。让作为根数据源的LINQ查询是不可变的(或者任何其他类型的IEnumerable<T>
,可以在关键部分之外安全地迭代,其中有很多)是一种安全的操作。 -
这不是一个非常常见的问题,很大一部分开发人员可能会遇到这个问题。
这充其量是第三方代码分析工具中的一个警告(即使在那里,由于给定的原因,它也可能无法成功)。它肯定不会出现在编译器的警告套件中。