在发布模式下未针对异步方法调用 IDisposable.Dispose()

2024-02-25

我在 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


我会把这个写下来,这个 Roslyn bug 非常令人讨厌,很容易破坏很多 VB.NET 程序。以一种非常丑陋且难以诊断的方式。

该错误很难发现,您必须使用反编译器查看生成的程序集。我将以极快的速度描述它。 Async Sub 中的语句被重写为状态机,代码片段中的特定类名称是 VB$StateMachine_1_buttonClick。你只能用像样的反编译器才能看到它。这MoveNext()该类的方法执行方法体中的语句。当您的异步代码运行时,会多次输入此方法。

MoveNext() 使用的变量需要是captured,将局部变量转换为类的字段。像你的window变量,稍后当Using语句结束并且需要调用Dispose()方法时将需要它。调试版本中该变量的名称是$VB$ResumableLocal_window$0。当您构建程序的发布版本时,编译器会尝试优化此类,但结果却很糟糕。它消除捕获并制作windowMoveNext() 的局部变量。这是非常错误的,当执行在Await,该变量将为 Nothing。因此它的 Dispose() 方法不会被调用。

这个 Roslyn bug 具有非常大的影响,它会破坏任何使用Using异步方法中的语句,其中语句主体包含 Await。这并不容易诊断,丢失的 Dispose() 调用经常未被检测到。除非像你这样的情况,它有非常明显的副作用。现在肯定有很多正在生产中运行的程序存在此错误。副作用是它们会“繁重”地运行,消耗比必要的更多的资源。该程序可能会以许多难以诊断的方式失败。

对于此错误有一个临时解决方法,请确保永远不要部署存在其他问题的 VB.NET 应用程序的调试版本。相反,请关闭优化器。选择发布版本并使用“项目”>“属性”>“编译”选项卡>“高级编译选项”> 取消选中“启用优化”复选框。

哎呀,这很糟糕。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在发布模式下未针对异步方法调用 IDisposable.Dispose() 的相关文章

随机推荐

  • 从另一个函数名计算一个函数名

    在 python 3 4 中 我希望能够出于测试目的制作一个非常简单的调度表 这个想法是有一个字典 键是要测试的函数名称的字符串 数据项是测试函数的名称 例如 myTestList myDrawFromTo myDrawLineDir my
  • 如何使用 animate 方法进行连续循环?

    如何使用一个连续循环动画animate 在这个例子中 我想做的就是无休止地旋转一个白色方块 myBall new Layer x 100 y 100 width 200 height 200 borderRadius 20px backgr
  • Excel VBA:获取单击按钮的行[重复]

    这个问题在这里已经有答案了 我正在尝试在 Excel 中创建一个按钮 将特定范围的单元格从活动工作簿复制到另一个工作簿 当我指定固定范围时 该范围的复制工作得很好 但我对如何找出单击的按钮的行感到困惑 每行包含 7 个左右的单元格 第 8
  • 无法获取总金额

    大家好 我已经解决了最初的问题 但现在它无法正确添加 我不确定该怎么做以及我哪里出了问题 任何帮助 将不胜感激 导入java util Scanner 公开课动物园 公共静态无效主 字符串 args int quantity confirm
  • 微调器的文本大小

    如何减小微调器的字体大小 我已将微调器大小减小到 35 像素 因此我的文本被切成两半 我怎么做 我也不希望事先选择任何东西 默认文本应该是 select some value 经过一些测试 有一个比继承 ArrayAdapter 更简单的方
  • 如何在自定义控件中包含光标(插入符号)?

    我被指派用 C 和 Windows 窗体制作自定义网格控件 我不确定的一件事是如何处理显示闪烁的光标 插入符号 以指示单元格编辑正在进行的位置以及将显示下一个字符 有谁知道这是如何使用标准文本框完成的 是否有一个标准框架结构可以为我做到这一
  • 列表理解中的 if/else

    我有一个清单xs包含字符串的混合物和None价值观 如何使用列表理解在每个字符串上调用函数 但将None价值观 而不是将它们传递给函数 I tried f x for x in xs if x is not None else 但它给出了S
  • 阿拉伯标签在 Geoserver 中无法正确显示

    我已随 Tomcat 安装了 geoserver 但文本标签无法正确显示 我在哪里可以设置geosever中的阿拉伯编码 标签在 QGIS 中显示得很好 但是当我将其发布到 geoserver 中时 我遇到了这个问题 1 https i s
  • 在 Bash 中比较两个字符串时出现“找不到命令”错误

    我的整个脚本目前是这样的 bin sh clear blanko Dummy Variablen variable Testvariable if variable blanko then echo Nichts da else echo
  • React setState 不更新状态

    所以我有这个 let total newDealersDeckTotal reduce function a b return a b 0 console log total tittal outputs correct total set
  • 如何增加 Google Cloud Run 中的内存限制?

    我正在使用 Cloud Run Cloud Firestore 构建一个简单的基于 Flask 的应用程序 有一种方法会带来大量数据 并且日志显示此错误 Memory limit of 244M exceeded with 248M use
  • 为什么 Python 装饰器不能跨定义链接?

    为什么以下两个脚本不等效 摘自另一个问题 了解 Python 装饰器 https stackoverflow com questions 739654 understanding python decorators def makebold
  • 在Webpack中构建dist文件夹后,如何将bundle.js和css文件移动到statics文件夹中?

    当我运行我的npm run build or npm run build dev 它在根目录中创建index html manage2 bundle js 和manage2 css 文件 我需要将这些文件移动到静态目录中 因此 下面生成的i
  • 有没有一种简单的方法可以在 Google 云中的项目之间克隆 SQL 实例?

    我想知道是否存在一种简单的方法可以在 Google Cloud 中的项目之间克隆 sql 实例 我知道我可以将数据导出到存储桶 请参阅img 1 但我发现这有点麻烦 如果有人有一个简单的方法来做到这一点 我们将不胜感激 没有 快速 方法可以
  • Pandas:合并数据框而不创建新列

    我有 2 个具有相同列的数据框 df1 pd DataFrame Abe 1 True Ben 2 True Charlie 3 True columns Name Number Other df2 pd DataFrame Derek 4
  • 使用 Python 加载 SQL_VARIANT 数据类型时出错

    我正在使用 Python 2 7 和 SQLAlchemy 0 7 8 来查询我没有创建的数据库 我在查询包含以下内容的表时遇到问题SQL VARIANT数据类型 我收到错误 sqlalchemy exc DBAPIError 错误 ODB
  • Flutter如何检测设备语言?

    我有一个问题 如何检测设备语言 并据此在应用程序最初启动时给出正确的语言 如果可能 请提供带有代码的示例 Calling Localizations localeOf context languageCode应该返回你的语言代码 如果未提供
  • 如果用户在浏览器中禁用了 JavaScript,如何使用不同的 CSS 样式表?

    我正在为某人开发一个网站 我使用的 CSS 样式需要 JavaScript 用于小屏幕上下拉导航栏的按钮 如果用户启用了 JavaScript 我如何使用一种样式表 如果用户禁用 JavaScript 我如何使用另一种样式表 有两种方法可以
  • 如何以良好的方式使用 SQL NULL 值和 JSON?

    Go 类型如Int64 and String不能存储空值 所以我发现我可以使用sql NullInt64 https golang org pkg database sql NullInt64 and sql NullString http
  • 在发布模式下未针对异步方法调用 IDisposable.Dispose()

    我在 VS2015 1 上使用 NET 4 6 1 在 VB NET 14 中编写了以下 WPF 示例应用程序 Class MainWindow Public Sub New InitializeComponent End Sub Priv