C# 为什么在foreach迭代中通过锁中的数组的屈服会使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

与Visual Studio 2010中使用的C#/.NET编译器相关的一个问题:在项目开发过程中,一位同事遇到了一种情况,即VS2010编译器在锁中使用现有代码时会崩溃。我们逐行分解代码,最终得出结论,在
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;
        }
    }
}