CLR System.NullReferenceException beim Erzwingen von 'Set Next Statement' in 'if' -Block

Hintergrun

Ich akzeptiere, dass dies nicht während der normalen Codeausführung auftreten kann, aber ich habe es beim Debuggen entdeckt und fand es interessant, es zu teilen.

Ich denke, das liegt am JIT-Compiler, würde mich aber über weitere Überlegungen freuen.

Ich habe dieses Problem mit VS2013 für das 4.5- und 4.5.1-Framework repliziert:

Installiere

Um diese Ausnahme zu sehenCommon Language Runtime Exceptions muss aktiviert sein:DEBUG > Exceptions...

Ich habe die Ursache des Problems in folgendem Beispiel zusammengefasst:

using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication6
{
    public class Program
    {
        static void Main()
        {
            var myEnum = MyEnum.Good;

            var list = new List<MyData>
            {
                new MyData{ Id = 1, Code = "1"},
                new MyData{ Id = 2, Code = "2"},
                new MyData{ Id = 3, Code = "3"}
            };

            // Evaluates to false
            if (myEnum == MyEnum.Bad) // BREAK POINT 
            {
                /*
                 * A first chance exception of type 'System.NullReferenceException' occurred in ConsoleApplication6.exe

                   Additional information: Object reference not set to an instance of an object.
                 */
                var x = new MyClass();

                MyData result;
                //// With this line the 'System.NullReferenceException' gets thrown in the line above:
                result = list.FirstOrDefault(r => r.Code == x.Code);

                //// But with this line, with 'x' not referenced, the code above runs ok:
                //result = list.FirstOrDefault(r => r.Code == "x.Code");
            }
        }
    }

    public enum MyEnum
    {
        Good,
        Bad
    }

    public class MyClass
    {
        public string Code { get; set; }
    }

    public class MyData
    {
        public int Id { get; set; }
        public string Code { get; set; }
    }
}
Zum Replizieren

Legen Sie einen Haltepunkt aufif (myEnum == MyEnum.Bad) und führen Sie den Code aus. Wenn der Haltepunkt erreicht ist, wirdSet Next Statement( Strg+Verschiebun+ F10) als erste Klammer desif Anweisung und laufe bis:

Nächste, Kommentarau die erste Lamda-Anweisung und Kommentari das zweite - so dasMyClass Instanz wird nicht verwendet. Führe den Prozess erneut aus (triff die Pause, erzwinge dasif Anweisung und Laufen). Sie werden sehen, dass der Code korrekt funktioniert:

Schließlich Kommentari die erste Lamda-Anweisung und Kommentarau das zweite - so dasMyClass instance ist benutzt. Dann überarbeiten Sie den Inhalt desif Anweisung in eine neue Methode:

using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication6
{
    public class Program
    {
        static void Main()
        {
            var myEnum = MyEnum.Good;

            var list = new List<MyData>
            {
                new MyData{ Id = 1, Code = "1"},
                new MyData{ Id = 2, Code = "2"},
                new MyData{ Id = 3, Code = "3"}
            };

            // Evaluates to false
            if (myEnum == MyEnum.Bad) // BREAK POINT 
            {
                MyMethod(list);
            }
        }

        private static void MyMethod(List<MyData> list)
        {
            // When the code is in this method, it works fine
            var x = new MyClass();

            MyData result;

            result = list.FirstOrDefault(r => r.Code == x.Code);
        }
    }

    public enum MyEnum
    {
        Good,
        Bad
    }

    public class MyClass
    {
        public string Code { get; set; }
    }

    public class MyData
    {
        public int Id { get; set; }
        public string Code { get; set; }
    }
}

Führen Sie den Test erneut aus und alles funktioniert korrekt:

Fazit

Ich gehe davon aus, dass der JIT-Compiler das lamda so optimiert hat, dass es immer null ist, und dass vor der Initialisierung der Instanz ein weiter optimierter Code ausgeführt wird.

Wie ich bereits erwähnt habe, könnte dies im Produktionscode niemals passieren, aber ich wäre gespannt, was passiert.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage