2016-02-23 14 views
9

Nach einer couple verzögerten Migration auf die .NET 4.6-Laufzeit war ich endlich mit der Umstellung auf die C# 6/VB14-Compiler bequem, bis ich ein kritisches Problem mit Iterator-Funktionen in VB stieß. NET verworfen lokale Variablen.VB.NET Iterator-Funktion verliert lokale Variablen

Im folgenden Codebeispiel wird eine NULL-Verweisausnahme für die Kommentarzeile ausgegeben, wenn sie in Visual Studio 2015/msbuild im Freigabemodus (optimiert) kompiliert wurde.

Module Module1 

    Sub Main() 
     For Each o As Integer In GetAllStuff() 
      Console.WriteLine(o.ToString()) 
     Next 

     Console.ReadKey() 

    End Sub 

    Private Iterator Function GetAllStuff() As IEnumerable(Of Integer) 
     Dim map As Dictionary(Of String, String) = New Dictionary(Of String, String) 
     Dim tasks As New List(Of Integer) 
     tasks.Add(1) 

     For Each task As Integer In tasks 
      Yield task 
     Next 

     'The value of map becomes null here under the new VB14 compiler in Release on .NET 4.6' 
     For Each s As String In map.Values 
      Yield 100 
     Next 
    End Function 

End Module 

Also, das ist ziemlich beängstigend.

Insbesondere das C# -Aquivalent dieses Codes wird ohne Problem ausgeführt. Noch wichtiger ist, dass dies unter früheren Versionen des VB-Compilers funktioniert (und auch funktioniert hat). Beim Vergleich der MSIL zwischen der von den beiden verschiedenen Compilern erzeugten Zustandsmaschine scheint der neue Compiler fast ausschließlich .locals für den lokalen Variablenspeicher zu verwenden, während der alte Compiler veränderbare Felder auf der Zustandsmaschine zum Speichern lokaler Werte verwendete.

Fehle ich etwas? Ich konnte keine Dokumentation einer brechenden Änderung mit Iteratoren in VB finden (ich kann mir auch nicht vorstellen, dass dies der Fall wäre), aber ich habe auch niemanden gefunden, der dieses Problem gelöst hat.

Dieses spezielle Beispiel kann durch Verschieben der Konstruktion von map nach der ersten foreach-Schleife gearbeitet werden, aber meine Sorge ist, dass ich keinen Sinn für den wahren Geschmack dieses Problems habe. Ich bin nicht daran interessiert, den Code so zu ändern, dass er einfach funktioniert. Wo sonst in unserer umfangreichen Codebasis könnte ich auf ein Problem stoßen? Ich habe das Problem unter Connect eingereicht, aber das fühlt sich oft wie ein schwarzes Loch an.

UPDATE

Jemand berichtet nur das gleiche Problem mit der Asynchron-Zustandsmaschine auf der Roslyn GitHub Seite: https://github.com/dotnet/roslyn/issues/9001

Hoffentlich beginnt ein wenig Aufmerksamkeit zu bekommen.

+0

Ich habe Ihren Code in VS2015 ausgeführt, gegen .NET Framework 4.5.2 kompiliert und dies erzeugt auch eine 'NullReferenceException'. Es scheint also, es ist nicht isoliert zu .NET 4.6 Runtime. –

+0

Wenn ich mit VS2013 gegen 4.5.2 oder 4.6 kompiliere, bekomme ich die 'NullReferenceException' nicht. Also, wie du sagst, ist das ein Compiler-Problem und kein Framework-Problem. –

+0

@Threadcreator: Dein Code funktioniert perfekt für mich. Verwenden von Windows 10 Pro (x64), Visual Studio 2015 Express für Windows Desktop. Targetframework: 4.5 – SiriSch

Antwort

1

Zunächst einmal, vielen Dank für die Aufmerksamkeit, die ich dem Roslyn-Team entgegengebracht habe.

ich die neueste Roslyn Quelle von https://github.com/dotnet/roslyn (Master-Zweig) gezogen habe, und fügte hinzu, eine zusätzliche Einheit Test zum BasicCompilerEmitTest Projekt, das wie folgt aussieht:

Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests 

Public Class KirillsTests 
    Inherits BasicTestBase 

    <Fact> 
    Public Sub IteratorVariableCaptureTest() 
    Dim source = 
<compilation name="Iterators"> 
    <file name="a.vb"> 
Imports System 
Imports System.Collections.Generic 

Module Module1 

    Sub Main() 
     For Each o As Integer In GetAllStuff() 
      Console.WriteLine(o.ToString()) 
     Next 

     Console.WriteLine("done") 
    End Sub 

    Private Iterator Function GetAllStuff() As IEnumerable(Of Integer) 
     Dim map As Dictionary(Of String, String) = New Dictionary(Of String, String) 
     Dim tasks As New List(Of Integer) 
     tasks.Add(1) 

     For Each task As Integer In tasks 
      Yield task 
     Next 

     'The value of map becomes null here under the new VB14 compiler in Release on .NET 4.6' 
     For Each s As String In map.Values 
      Yield 100 
     Next 
    End Function 

End Module 
    </file> 
</compilation> 

    Dim expectedOutput = <![CDATA[1 
done]]> 

    Dim compilation = CompilationUtils.CreateCompilationWithReferences(source, references:=LatestVbReferences, options:=TestOptions.DebugExe) 
    CompileAndVerify(compilation, expectedOutput:=expectedOutput) 
    CompileAndVerify(compilation.WithOptions(TestOptions.ReleaseExe), expectedOutput:=expectedOutput) 
    End Sub 

End Class 

wie eine gewundene Chaos aussieht Dies kann auf XElement und XCData, aber dieses Format wird von anderen Roslyn-Komponententests verwendet.

Ich habe nur eine Änderung den Code, den Sie in Ihrer Frage geschrieben - das ist Console.ReadKey() mit Console.WriteLine("done") ersetzt, so dass ich den erfolgreichen Abschluss verfolgen könnte (wie CompileAndVerify einfach Ausnahmen ignoriert).

Der obige Test besteht. Es gibt keine NullReferenceException auf map.Values Zugang, und der Ausgang ist:

 
1 
done 

... wie erwartet. Es scheint also, dass Ihr Fehler behoben wurde - obwohl ich nicht sagen kann, ob der Fix mit Visual Studio 2015 Update 2 geliefert wird oder nicht.

Die async variable capture issue wurde von pull request #7693 festgelegt, aber DataFlowPass.SetSlotUnassigned wurde überarbeitet, da (aufgeteilt in 2 Methoden und modifiziert) so kann ich nicht bestätigen, ob der Iterator Problem, das Sie von diesem bestimmten Pull-Anforderung festgelegt entdeckt wurde, oder durch einen anderen Code ändern.

+2

Das wird ja mit dem Update 2 CTP angesprochen. Ich blies einen Telefonfreund mit Microsoft-Support, um weitere Details zu dem spezifischen Update zu erhalten, und er wird wieder mit den mir zur Verfügung gestellten Informationen aktualisiert. Leider hat sich 2015/4.6 wie eine lange CTP gefühlt. Platform Stabilität war so ein großer Verkaufsargument für .NET ... – roken

+1

@roken, gut zu wissen, dass der Fix bald ausgeliefert wird. Roslyn ist immer noch in den Kinderschuhen und du hast recht, es hat ein wenig experimentelles Gefühl. Es ist eine aufregende Zeit in vielerlei Hinsicht, aber nicht immer aus guten Gründen, wie diese Frage zeigt. –