IDisposable 到底需要啥? [复制]

Posted

技术标签:

【中文标题】IDisposable 到底需要啥? [复制]【英文标题】:What exactly is IDisposable needed for? [duplicate]IDisposable 到底需要什么? [复制] 【发布时间】:2013-01-11 07:53:48 【问题描述】:

可能重复:Proper use of the IDisposable interface

我试图从书籍、互联网和 *** 上找到我的问题的实际答案,但到目前为止没有任何帮助我,所以希望我能准确地表达我的问题以使其有意义。

一般来说,我总是发现如何释放内存的基本用法相同,大约是。如下,我确实理解代码本身:

public class MyClass : IDisposable

    bool disposed = false;
    public void Dispose()
    
        if (!disposed)
        
        Dispose(true);
        GC.SuppressFinalize(this);
        disposed = true;
        
    

    protected virtual void Dispose(bool disposing)
    
        if (disposing)
        
        //free managed ressources
        
    // free other ressources
    

    ~MyClass()
    
        Dispose(false);
    

方法的工作方式完全有意义。但现在我的问题是:为什么我们需要基类 IDisposable?在此代码示例中,我们定义了一个名为 Dispose() 的方法。正如我在各处读到的那样,该方法是 IDisposable 的一部分,但我们刚刚在 MyClass 中定义了该方法,如果我们不实现基类 IDisposable 或者我对这个假设有误,这段代码仍然可以工作?

我对 C# 并不完全陌生,但我还有很多东西要学,所以希望有人能在这里引导我朝着正确的方向前进。我检查了另一个具有相同问题的帖子,但找不到它,所以如果它确实存在并且它确实回答了我的问题,请引导我到那里,我将删除此帖子。

【问题讨论】:

IDisposable 不是 [base] 类。这是一个interface。为什么在 C# 中需要 any 接口? (IDisposable 的作用不亚于其他接口。) 感谢您的快速回复。好吧,既然我还有很多关于 C# 的知识,请回答你刚才问我的问题。 感谢您的链接,在我看来,讽刺有点不必要。我不知道基类和接口之间有如此大的区别 在任何情况下,接口都提供了一个主名类型(通过给定名称已知的类型/契约)而不影响对象的类层次结构。这允许在同一接口中使用不同类型的对象;一些接口,如 IDisposable(或 ISerializable)也建立了各种使用“规则和模式”。请参阅相应的文档。 我们能否减少重复的回答? 【参考方案1】:

它与 C# 编译器的 using 块一起使用。

【讨论】:

虽然我不认为这是一个“完整”的答案,但using(以及通过Dispose() 进行的更多手动生命周期管理)是IDisposable 的唯一原因......所以+1。 【参考方案2】:

IDisposable.Dispose 的实际实现调用了 Dispose(bool) 的基类实现。从这个类继承的任何人现在都需要处理以下任务:

public override Dispose(bool disposing)

    base.Dispose(disposing);
    //my disposal code

使用这种公认的模式,继承者可以在不破坏基类的处置的情况下扩展处置代码。

通常,如果您没有非托管资源可以处置并且可以负担得起您的课程,您可以使用以下代码简化问题:

public sealed class SomeDisposable:IDisposable

    public void Dispose()
    
       //just go ahead and clean up
       //because we're sealed, no-one can ever break
       //this code via inheritance
    
    //~SomeDisposable()
    //
    //   if this is being called then it will be called
    //   on all referenced and unrooted IDisposables too
    //   If everything is managed, that means we've got nothing
    //   left to clean up, so we can omit this Finalizer 
    //

【讨论】:

感谢和 +1 添加密封类。【参考方案3】:

你是对的,因为你的析构函数~MyClass调用Dispose,似乎不需要接口IDisposable

Dispose 不仅仅由析构函数调用。当您想要释放非托管资源时,您可以在代码中自己调用它。之所以需要它,是因为您不知道何时调用析构函数(这取决于垃圾收集器)。

最后,IDisposable.Dispose 在您使用 using 时被调用。

using(MyDisposableClass myObject = new MyDisposableClass())

    // My Code

相当于:

MyDisposableClass myObject = new MyDisposableClass();
try

    // My Code

finally

    myObject.Dispose();

【讨论】:

这是一个很好的解释,感谢您的快速澄清 您也不能显式调用 C# 类析构函数。它首先在 GC 启动时调用,而不是 .Dispose() ,后者通常由用户代码显式调用。【参考方案4】:

实施 IDispose 为您提供了一个地方来释放您“持有”的资源,例如流、句柄或数据库连接。

从垃圾收集器调用Dispose(),基本上是询问对象:“如果有什么你不再需要,但我想不通;现在释放它;清理!”

在某种意义上类似于 C++ 中的析构函数

不同之处在于 C++ 的析构函数会立即被调用,而 Dispose() 会更及时。

在大多数情况下,您不需要实现它。 GC 足够聪明,可以在 90% 的情况下找出如何释放已用资源。

但是例如:释放流使用的内存并不会自动关闭 流并释放数据库连接也不会关闭它。

实现 Dispose 允许您在释放对象时关闭文件:

internal class Something : IDisposable 
private Stream stream;

public void SomeMethod() 
    stream.Write("nskdns");


public void Dispose() 
    if (stream != null) 
        stream.Close();
    

此外:实现 IDispose 让您有机会在 using 语句中使用类:

public void Example() 
    using (var x = new Something())
    
        x.SomeMethod();
    

确保 x 在被 GC 释放时总是会关闭已使用的流。

我更喜欢类上的专用 Close() 方法,以允许显式关闭流,而不是依赖 GC 并调用 Dispose()

【讨论】:

以上是关于IDisposable 到底需要啥? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

c# 中最简单的 IDisposable 模式是啥? [复制]

我应该何时实施 IDisposable? [复制]

主索引和二级索引到底有啥区别? [复制]

使用 Spring Data JPA 的 JpaRepository 和 CrudRepository 之间到底有啥区别? [复制]

using关键字和IDisposable接口有啥关系?

*args 和 **kwargs 是啥意思? [复制]