Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 应该";处置;是否仅用于包含非托管资源的类型?_C#_Garbage Collection_Idisposable_Finalizer_Finalization - Fatal编程技术网

C# 应该";处置;是否仅用于包含非托管资源的类型?

C# 应该";处置;是否仅用于包含非托管资源的类型?,c#,garbage-collection,idisposable,finalizer,finalization,C#,Garbage Collection,Idisposable,Finalizer,Finalization,我最近与一位同事讨论了Dispose的价值以及实现IDisposable的类型 我认为对应该尽快清理的类型实施IDisposable,是有价值的,即使没有非托管资源要清理 我的同事有不同的想法;如果没有任何非托管资源,则无需实现IDisposable,因为您的类型最终将被垃圾收集 我的观点是,如果您有一个希望尽快关闭的ADO.NET连接,那么实现IDisposable和使用新的MythingWithConnection()是有意义的。我的同事回答说,实际上,ADO.NET连接是一种非托管资源。我

我最近与一位同事讨论了
Dispose
的价值以及实现
IDisposable
的类型

我认为对应该尽快清理的类型实施
IDisposable
,是有价值的,即使没有非托管资源要清理

我的同事有不同的想法;如果没有任何非托管资源,则无需实现
IDisposable
,因为您的类型最终将被垃圾收集

我的观点是,如果您有一个希望尽快关闭的ADO.NET连接,那么实现
IDisposable
使用新的MythingWithConnection()
是有意义的。我的同事回答说,实际上,ADO.NET连接是一种非托管资源。我对他的回答的回答是,一切最终都是非托管资源

我知道如果调用了
Dispose
,您将释放托管和非托管资源,但是如果通过finalizer/destructor调用,则只有释放非托管资源(不久前还写了关于如何释放的博客)


所以,我的问题是,如果您的类型不包含非托管资源,那么是否值得实现
IDisposable

IDisposable有不同的有效用途。一个简单的例子是保存一个打开的文件,当您不再需要它时,需要在某个时刻将其关闭。当然,您可以提供一个方法
Close
,但是将它放在
Dispose
中,并使用类似
的模式使用(var f=new MyFile(path)){/*process it*/}
将更加安全

一个更流行的例子是保存一些其他的
IDisposable
资源,这通常意味着您需要提供自己的
Dispose
,以便也处理它们

通常,只要您想要对任何东西进行确定性销毁,就需要实现
IDisposable

我的观点和你的不同之处在于,只要某些资源需要确定性销毁/释放,我就实施
IDisposable
,而不是尽快实施。在这种情况下,依赖垃圾收集不是一种选择(与您同事的说法相反),因为它发生在不可预测的时刻,实际上可能根本不会发生

事实上,任何资源都是不受保护的,这并不意味着什么:开发人员应该考虑“何时以及如何正确地处置这个对象”,而不是“它在保护下是如何工作的”。无论如何,底层实现可能会随时间而变化

实际上,C和C++之间的主要区别之一是缺省确定性破坏的缺失。 IDISPOLISTABLE <代码>来结束这个间隙:您可以命令确定性破坏(虽然不能保证客户端正在调用它,但在C++中,同样不能确保客户端调用对象上的代码>删除< /代码>)。
小补充:释放资源和尽快释放资源之间的区别是什么?实际上,这些是不同的(尽管不是完全正交的)概念

如果要确定地释放资源,这意味着客户机代码应该可以说“现在,我希望释放此资源”。实际上,这可能不是释放资源的最早时刻:持有资源的对象可能已经从资源中获得了它所需要的一切,因此它可能已经释放了资源。另一方面,即使在对象的
Dispose
运行之后,对象也可能选择保留(通常是非托管的)资源,仅在finalizer中清理它(如果长时间保留资源不会产生任何问题)

因此,为了尽快释放资源,严格来说,
Dispose
是不必要的:只要对象意识到不再需要资源,它就可以释放资源<但是,code>Dispose提供了一个有用的提示,表明不再需要对象本身,因此如果合适的话,可能会在此时释放资源


还有一个必要的补充:需要确定性释放的不仅仅是非托管资源!这似乎是这个问题的答案之间意见分歧的关键点之一。一个人可以有纯粹的想象结构,这可能需要被确定性地释放

例如:访问某个共享结构的权限(想想看)、巨大的内存块(假设您正在手动管理该程序的部分内存)、使用其他程序的许可证(假设您不允许同时运行某个程序的X个以上副本),在这里,要释放的对象不是非托管资源,而是执行/使用某些操作的权利,这是程序逻辑的纯粹内部构造



小添加:这里是一个小列表,列出了[ab]使用
IDisposable
:。

不,它不是仅用于非托管资源


建议使用框架调用的基本清理内置机制,使您能够清理所需的任何资源,但最合适的是自然的非托管资源管理。

如果您聚合了
IDisposable
s,那么您应该实现该接口,以便及时清理这些成员。在您引用的ADO.Net连接示例中,
myConn.Dispose()

但是,我认为,在这种情况下,说一切都是非托管资源是不正确的。我也不同意你同事的看法

internal class Class1 : IDisposable
{
    public Class1()
    {
        Console.WriteLine("Construct");
    }

    public void Dispose()
    {
        Console.WriteLine("Dispose");
    }

    ~Class1()
    {
        Console.WriteLine("Destruct");
    }
}
static void Main(string[] args)
{
    for (int i = 0; i < 10; i++)
    {
        Class1 obj = new Class1();
        obj.Dispose();
    }

    Console.ReadKey();
}
using (WindowsImpersonationContext context = SomeUserIdentity.Impersonate()))
{
    // do something as SomeUser
}

// back to your user
  Cursor savedCursor = Cursor.Current;

  try {
    Cursor.Current = Cursors.WaitCursor;

    SomeLongOperation();
  }
  finally {
    Cursor.Current = savedCursor;
  }
  using (new WaitCursor()) {
    SomeLongOperation();
  }
  public sealed class WaitCursor: IDisposable {
    private Cursor m_Saved;

    public Boolean Disposed {
      get;
      private set;
    }

    public WaitCursor() {
      Cursor m_Saved = Cursor.Current;
      Cursor.Current = Cursors.WaitCursor;
    }

    public void Dispose() {
      if (!Disposed) {
        Disposed = true;
        Cursor.Current = m_Saved;
      }
    }
  }
  using (new WaitCursor()) {
    using (new RegisterServerLongOperation("My Long DB Operation")) {
      SomeLongRdbmsOperation();  
    }

    SomeLongOperation();
  }