CA1001 实现 IDisposable 在异步方法上

32

考虑以下代码:

public class Test
{
    public async Task Do()
    {
        await Task.Delay(200);

        using (var disposable = new Disposable())
        {
            disposable.Do();
        }
    }
}

public class Disposable : IDisposable
{
    public void Do()
    {
    }

    public void Dispose()
    {
    }
}

当我在Visual Studio中运行代码分析时,我收到一个警告:

警告 CA1001:在 Test.< Do>d__0 上实现 IDisposable,因为它创建了以下 IDisposable 类型的成员:'Disposable'。

为什么会有这个警告?Disposable类被正确释放并且我没有将其存储在任何地方。

此外,这似乎对分析器来说是可以接受的:

public class Test
{
    public void Do()
    {
        using (var disposable = new Disposable())
        {
            disposable.Do();
        }
    }
}

5
可以说,分析器中存在一个错误。编译器将其转换为状态机代码,其中可处理的对象被提升到闭包类中,作为字段暴露出来,这时代码分析就会发出警告。它并不知道编译器生成的代码无论如何都会处理对象的释放,而且该类不打算由客户端进行处理。由于用户显然不能修改编译器生成的代码,因此警告是没有意义的(即使编译器生成的代码最终被发现存在错误!) - Jeroen Mostert
2个回答

29

这是因为编译器从你的异步方法生成状态机,而该状态机类(在本例中命名为<Do>d__0)包含类型为Disposable的字段,但它本身并没有实现IDisposable接口。分析器分析编译器生成的代码(并且此<Do>d__0类标有CompilerGenerated属性)没有太多意义。幸运的是,有一个设置可以让代码分析器避免编译器生成的代码:转到项目属性,选择“代码分析”选项卡,然后勾选“抑制来自生成的代码的结果”,这个警告就会消失。


我已经检查了设置,但仍然出现错误,有什么想法为什么会这样? - CSCoder

10

如果你查看IL代码,你会发现一个名为<Do>d__0的类被创建来处理异步事务:

// Nested Types
.class nested private auto ansi sealed beforefieldinit '<Do>d__0'
    extends [mscorlib]System.Object
    implements [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine
{

后来,这个类创建了一个 Disposable 实例:

IL_0074: newobj instance void ConsoleApp1.Disposable::.ctor()

这是触发 CA1001 警告的类,因为 CA1001 检查 IL,并且生成的类没有实现 IDisposable。在这个特定的类上,您可以安全地忽略 CA1001 警告。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接