为什么通过锁内数组的foreach迭代中的yield会导致VS2010编译器崩溃?

本文关键字:VS2010 崩溃 编译器 yield 迭代 数组 为什么 foreach | 更新日期: 2023-09-27 18:15:43

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

我们继续在Visual Studio 2013上测试这个复制样本,它没有出现同样的问题。这个编译器问题似乎与VS2010中使用的编译器有关,并且在VS2012中可能会或可能不会有相同的问题(我们无法访问它用于测试目的)。此外,我们已经测试了使用常规for循环不会崩溃。因此,问题是,为什么VS2010编译器崩溃?它在做什么让它如此困惑?

(是的,这个问题主要是为了了解编译器)

为什么通过锁内数组的foreach迭代中的yield会导致VS2010编译器崩溃?

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

理论上,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

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

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;
        }
    }
}

所以这可能只是一个CSC bug或者更微妙的东西