我在 VS2015.1 上使用 .NET 4.6.1 在 VB.NET 14 中编写了以下 WPF 示例应用程序:
Class MainWindow
Public Sub New()
InitializeComponent()
End Sub
Private Async Sub Button_Click(sender As Object, e As RoutedEventArgs)
MessageBox.Show("Pre")
Using window = New DisposableWindow()
window.Show()
For index = 1 To 1
Await Task.Delay(100)
Next
End Using
MessageBox.Show("Post")
End Sub
Class DisposableWindow
Inherits Window
Implements IDisposable
Public Sub Dispose() Implements IDisposable.Dispose
Me.Close()
MessageBox.Show("Disposed")
End Sub
End Class
End Class
下面的示例产生以下输出:
- 调试模式:预调试、已部署、后调试
- 发布模式:前发布、后发布
这很奇怪。为什么调试模式执行此代码的方式与发布模式不同...?
当我将 using 块更改为手动 try/finally 块时,对 window.Dispose() 的调用甚至会抛出 NullReferenceException:
Dim window = New DisposableWindow()
Try
window.Show()
For index = 1 To 1
Await Task.Delay(100)
Next
Finally
window.Dispose()
End Try
甚至更奇怪的事情是:当排除 for 循环时,示例可以完美运行。我只让 For 循环运行一次,以指定产生问题的最小循环量。也可以随意将 For 循环替换为 While 循环。它产生与 For 循环相同的行为。
Works:
Using window = New DisposableWindow()
window.Show()
Await Task.Delay(100)
End Using
现在您可能会想:“这很奇怪!”。情况变得更糟。
我还在 C# (6) 中制作了完全相同的示例,它运行得很好。因此,在 C# 中,调试和发布模式都会产生“Pre、Dispose、Post”作为输出。
示例可以在这里下载:
http://www.filedropper.com/vbsample http://www.filedropper.com/vbsample
http://www.filedropper.com/cssample http://www.filedropper.com/cssample
我现在很困惑。这是 .NET Framework 的 VB.NET 堆栈中的错误吗?或者我是否试图完成一些奇怪的事情,幸运的是,这似乎可以在 C# 中工作,部分在 VB.NET 中工作?
Edit:
做了更多测试:
- 在发布模式下禁用 VB.NET 中的编译器优化,使其行为类似于调试模式(如预期,但想对其进行测试,以防万一)。
- 当我以 .NET 4.5(async/await 可用的最早版本)为目标时,也会出现此问题。
Update:
此问题已得到解决。 1.2 版本计划公开发布,但 master 分支中的最新版本应该包含修复程序。
See: https://github.com/dotnet/roslyn/issues/7669 https://github.com/dotnet/roslyn/issues/7669