为什么通过锁内的数组进行foreach迭代的屈服会使VS2010编译器崩溃?

Roe*_*den 7 .net c# compiler-construction visual-studio-2010

与Visual Studio 2010中使用的C#/.NET编译器相关的问题:在项目开发期间,一位同事遇到了VS2010编译器在使用锁内现有代码时崩溃的情况.我们逐行分开代码,最终得出结论,在锁定语句中使用yield return内部a foreach到数组会使编译器崩溃.可以使用以下代码重现该问题:

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我们继续在Visual Studio 2013上测试这个复制样本,但它没有出现同样的问题.此编译器问题似乎与VS2010中使用的编译器有关,并且在VS2012中可能会或可能不会出现相同的问题(我们无法访问它以进行测试).此外,我们测试过使用常规for循环不会崩溃.因此问题是,为什么VS2010编译器会崩溃?这是多么令人困惑的事情呢?

(是的,这主要是为了了解编译器而感兴趣的问题)

Vai*_*hav 3

好吧,也许这不能解决问题,但这是我的研究..

理论上,Jon Skeet 表示,yield 与锁一起使用时根本不会产生任何问题,因为锁分别在第一个和最后一个“MoveNext”迭代块之前和之后获取和释放。

更多内容请参见此处

当我亲自尝试您的代码时,编译器抛出以下(内部)错误:

Error   6   Internal Compiler Error (0xc0000005 at address 1332695D): likely culprit is 'TRANSFORM'.

An internal error has occurred in the compiler. To work around this problem, try simplifying or changing the program near the locations listed below. Locations at the top of the list are closer to the point at which the internal error occurred. Errors such as this can be reported to Microsoft by using the /errorreport option.
    ConsoleApp1
Run Code Online (Sandbox Code Playgroud)

但是,对类进行以下修改是有效的:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以可能只是CSC 错误或更微妙的问题。

  • 编译器永远不应该崩溃,所以这绝对是一个错误。 (4认同)