为什么退出“using”会调用意外的Dispose()?

Why exiting "using" invokes unexpected Dispose()?

提问人:HonanLi 提问时间:2/23/2022 最后编辑:Lance U. MatthewsHonanLi 更新时间:2/23/2022 访问量:81

问:

这是我的情况:

class A : IDisposable
{
    public void Dispose() { Console.WriteLine("A Dispose"); }
}

class B : A
{
    public new void Dispose(){ Console.WriteLine("B Dispose"); }
}

class Program
{
    static void Main(string[] args)
    {
        using (B b = new B())
        {
        }
    }
}

最终输出为“A Dispose”。 我读过一些文档,其中介绍了覆盖和新的区别,并且告诉人们“使用”实质上等于“尝试最终”。但是我仍然无法回答为什么它不是自动调用的 B::D ispose。 比较下面的输出是“B Dispose”

B b = new B();
try
{
}
finally
{
    b.Dispose();
}

请帮忙,我错过了。

C# .NET 继承 idisposable using-statement

评论

3赞 2/23/2022
实现派生类 MSDN 的释放模式
3赞 Charlieface 2/23/2022
有什么令人惊讶的?您没有,因此没有实现 .换句话说,你不能用显式实现来做是无效的newoverrideBIDisposable.Disposenewnew void IDisposable.Dispose(){ Console.WriteLine("B Dispose"); }
0赞 Damien_The_Unbeliever 2/23/2022
new本质上是“我想重用我的基类使用过的名称”。如果您为该方法使用了任何其他名称,则不必使用,而且更明显的是,它与同名基类的方法无关。new

答:

2赞 Etienne de Martel 2/23/2022 #1

根据 C# 语言规范,对于引用类型:

using (ResourceType resource = «expression» ) «statement»

相当于

{
    ResourceType resource = «expression»;
    try {
        «statement»;
    }
    finally {
        IDisposable d = (IDisposable)resource;
        if (d != null) d.Dispose();
    }
}

正如你所看到的,资源首先被强制转换为 ,这意味着 ' 是被调用的资源,因为 只是隐藏它而不是覆盖它。IDisposableADisposeBDispose

如果要在类层次结构中正确实现,请参阅文档中的最佳实践IDisposable

评论

0赞 Etienne de Martel 2/23/2022
如果 finally 的实现是 简单而不是 ,那么 就是被调用的那个,因为它隐藏了 的 。这不是这里发生的事情,OP在问为什么。resource.Dispose()((IDisposable)resource).Dispose()BDisposeADispose
0赞 Etienne de Martel 2/23/2022
啊,很公平。我会澄清这部分。