C# 为什么在foreach迭代中通过锁中的数组的屈服会使VS2010编译器崩溃?
与Visual Studio 2010中使用的C#/.NET编译器相关的一个问题:在项目开发过程中,一位同事遇到了一种情况,即VS2010编译器在锁中使用现有代码时会崩溃。我们逐行分解代码,最终得出结论,在C# 为什么在foreach迭代中通过锁中的数组的屈服会使VS2010编译器崩溃?,c#,.net,visual-studio-2010,compiler-construction,C#,.net,Visual Studio 2010,Compiler Construction,与Visual Studio 2010中使用的C#/.NET编译器相关的一个问题:在项目开发过程中,一位同事遇到了一种情况,即VS2010编译器在锁中使用现有代码时会崩溃。我们逐行分解代码,最终得出结论,在foreach中通过lock语句中的数组使用yield return,会使编译器崩溃。可使用以下代码复制此问题: using System; using System.Collections.Generic; namespace PlayGround { public static
foreach
中通过lock语句中的数组使用yield return
,会使编译器崩溃。可使用以下代码复制此问题:
using System;
using System.Collections.Generic;
namespace PlayGround
{
public static class Program
{
private static readonly object SyncRoot = new object();
private static IEnumerable<int> EnumerableWithLock()
{
lock (SyncRoot)
{
foreach (var i in new int[1])
{
yield return i;
}
}
}
public static void Main()
{
foreach (var i in EnumerableWithLock())
{
Console.WriteLine(i);
}
}
}
}
使用系统;
使用System.Collections.Generic;
命名空间操场
{
公共静态类程序
{
私有静态只读对象SyncRoot=新对象();
私有静态IEnumerable EnumerableWithLock()
{
锁定(同步根)
{
foreach(新整数[1]中的变量i)
{
收益率i;
}
}
}
公共静态void Main()
{
foreach(EnumerableWithLock()中的变量i)
{
控制台写入线(i);
}
}
}
}
我们继续在Visual Studio 2013上测试此复制样本,但它没有出现相同的问题。此编译器问题似乎与VS2010中使用的编译器有关,在VS2012中可能存在或不存在相同的问题(出于测试目的,我们无法访问它)。此外,我们还测试了使用常规for
循环不会崩溃。因此,问题是,为什么VS2010编译器会崩溃?是什么让它如此困惑
(是的,这主要是为了了解编译器而提出的问题)好吧,也许这并不能解决问题,但这是我的研究 从理论上讲,Jon Skeet说,当与锁一起使用时,屈服不会产生任何问题,因为锁是在第一个和最后一个“MoveNext”迭代块之前和之后获取和释放的 更多关于这个 当我亲自尝试您的代码时,编译器抛出了以下(内部)错误: 但是,对该类的以下修改有效:
public static class Program
{
//private static readonly object SyncRoot = new object();
//private static IEnumerable<int> EnumerableWithLock()
//{
// lock (SyncRoot)
// {
// foreach (var i in new int[1])
// {
// yield return i;
// }
// }
//}
public static void Main()
{
SomeClass sc = new SomeClass();
foreach (var i in sc.EnumerableWithLock())
{
Console.WriteLine(i);
}
Console.ReadLine();
}
}
public class SomeClass
{
private static readonly object SyncRoot = new object();
int[] i = { 1, 2, 3, 4, 5 };
List<int> retval = new List<int>();
public IEnumerable<int> EnumerableWithLock()
{
lock (SyncRoot)
{
foreach (var number in i)
{
retval.Add(number);
}
return retval;
}
}
}
公共静态类程序
{
//私有静态只读对象SyncRoot=新对象();
//私有静态IEnumerable EnumerableWithLock()
//{
//锁定(同步根)
// {
//foreach(新整数[1]中的变量i)
// {
//收益率i;
// }
// }
//}
公共静态void Main()
{
SomeClass sc=新的SomeClass();
foreach(sc.EnumerableWithLock()中的变量i)
{
控制台写入线(i);
}
Console.ReadLine();
}
}
公共类
{
私有静态只读对象SyncRoot=新对象();
int[]i={1,2,3,4,5};
List retval=新列表();
公共IEnumerable EnumerableWithLock()
{
锁定(同步根)
{
foreach(i中的变量编号)
{
返回。添加(编号);
}
返回返回;
}
}
}
因此,它可能只是一个CSC错误或更微妙的东西。如果编译器真的崩溃了(你没有提到导致这个结论的症状),那么它就是一个错误,简单明了。lock、foreach和yield都是“神奇”的关键字,它们将被转换成其他代码段,这三者之间的交互很可能(特别是yield关键字,它可能是这里涉及最自动化代码的关键字)编译器中有一个bug。编译器永远不会崩溃,所以这肯定是个bug。
public static class Program
{
//private static readonly object SyncRoot = new object();
//private static IEnumerable<int> EnumerableWithLock()
//{
// lock (SyncRoot)
// {
// foreach (var i in new int[1])
// {
// yield return i;
// }
// }
//}
public static void Main()
{
SomeClass sc = new SomeClass();
foreach (var i in sc.EnumerableWithLock())
{
Console.WriteLine(i);
}
Console.ReadLine();
}
}
public class SomeClass
{
private static readonly object SyncRoot = new object();
int[] i = { 1, 2, 3, 4, 5 };
List<int> retval = new List<int>();
public IEnumerable<int> EnumerableWithLock()
{
lock (SyncRoot)
{
foreach (var number in i)
{
retval.Add(number);
}
return retval;
}
}
}