rok*_*ken 9 .net vb.net msbuild visual-studio compiler-bug
在几个 showstoppers延迟迁移到.NET 4.6运行时之后,我终于习惯于转移到C#6/VB14编译器,直到遇到VB.NET中的迭代器函数抛弃局部变量的关键问题.
在Visual Studio 2015/msbuild中以发布模式(优化)编译时,以下代码示例将在注释行上抛出空引用异常.
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
Run Code Online (Sandbox Code Playgroud)
所以,这非常可怕.
值得注意的是,此代码的C#等效执行没有问题.更重要的是,这在VB编译器的早期版本下工作(并且已经工作).比较两个不同编译器创建的状态机之间的MSIL,新编译器似乎几乎只使用.locals用于本地变量存储,而旧编译器在状态机上使用可变字段来保存本地值.
我错过了什么吗?我无法在VB中找到任何与迭代器发生重大变化的文档(我也无法想象会出现这种情况),但也没有发现其他人遇到过这个问题.
这个特殊的例子可以通过将构造移动map
到第一个foreach循环之后来解决,但是我担心的是我对这个问题的真实味道没有任何意识.我没有兴趣修改代码"只是让它工作." 在我们广泛的代码库中的其他地方,我可能会遇到同样的问题吗?我已经在Connect上提交了这个问题,但这通常感觉像是一个黑洞.
UPDATE
有人刚刚在Roslyn GitHub页面上报告了与异步状态机相同的问题:https: //github.com/dotnet/roslyn/issues/9001
希望这开始得到一点关注.
首先,感谢您关注我向 Roslyn 团队提出的问题。
我已经从https://github.com/dotnet/roslyn (主分支)提取了最新的 Roslyn 源代码,并向 BasicCompilerEmitTest 项目添加了一个额外的单元测试,如下所示:
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
Run Code Online (Sandbox Code Playgroud)
XElement
由于使用情况,这可能看起来像一团混乱XCData
,但这是其他 Roslyn 单元测试使用的格式。
我只对您在问题中发布的代码进行了一项更改 - 即替换Console.ReadKey()
为Console.WriteLine("done")
,以便我可以跟踪成功完成情况(只是CompileAndVerify
忽略异常)。
以上测试通过。没有NullReferenceException
访问map.Values
,输出是:
1 完毕
...正如预期的那样。因此,您的错误似乎已得到修复 - 尽管该修复是否会随 Visual Studio 2015 Update 2 一起提供,我无法确定。
异步变量捕获问题已由Pull request #7693修复,但DataFlowPass.SetSlotUnassigned
此后已被重写(分为 2 个方法并进行修改),因此我无法确认您发现的迭代器问题是否已由该特定 Pull Request 或其他一些代码更改修复。
归档时间: |
|
查看次数: |
344 次 |
最近记录: |