简体   繁体   English

C#中Finalize/Dispose方法的使用

[英]Use of Finalize/Dispose method in C#

C# 2008 C# 2008

I have been working on this for a while now, and I am still confused about the use of finalize and dispose methods in code.我已经研究了一段时间了,我仍然对在代码中使用 finalize 和 dispose 方法感到困惑。 My questions are below:我的问题如下:

  1. I know that we only need a finalizer while disposing unmanaged resources.我知道在处理非托管资源时我们只需要一个终结器。 However, if there are managed resources that make calls to unmanaged resources, would it still need to implement a finalizer?但是,如果存在调用非托管资源的托管资源,它是否仍然需要实现终结器?

  2. However, if I develop a class that doesn't use any unmanaged resource - directly or indirectly, should I implement the IDisposable to allow the clients of that class to use the 'using statement'?但是,如果我开发一个不直接或间接使用任何非托管资源的类,我是否应该实现IDisposable以允许该类的客户端使用“using 语句”?

    Would it be feasible to implement IDisposable just to enable clients of your class to use the using statement?实现 IDisposable 只是为了让您的类的客户能够使用 using 语句是否可行?

     using(myClass objClass = new myClass()) { // Do stuff here }
  3. I have developed this simple code below to demonstrate the Finalize/dispose use:我在下面开发了这个简单的代码来演示 Finalize/dispose 使用:

     public class NoGateway : IDisposable { private WebClient wc = null; public NoGateway() { wc = new WebClient(); wc.DownloadStringCompleted += wc_DownloadStringCompleted; } // Start the Async call to find if NoGateway is true or false public void NoGatewayStatus() { // Start the Async's download // Do other work here wc.DownloadStringAsync(new Uri(www.xxxx.xxx)); } private void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { // Do work here } // Dispose of the NoGateway object public void Dispose() { wc.DownloadStringCompleted -= wc_DownloadStringCompleted; wc.Dispose(); GC.SuppressFinalize(this); } }

Question about the source code:关于源代码的问题:

  1. Here I have not added the finalizer, and normally the finalizer will be called by the GC, and the finalizer will call the Dispose.这里我没有添加终结器,一般情况下终结器会被GC调用,终结器会调用Dispose。 As I don't have the finalizer, when do I call the Dispose method?由于我没有终结器,我什么时候调用 Dispose 方法? Is it the client of the class that has to call it?是类的客户端必须调用它吗?

    So my class in the example is called NoGateway and the client could use and dispose of the class like this:因此,我在示例中的类称为 NoGateway,客户端可以像这样使用和处置该类:

     using(NoGateway objNoGateway = new NoGateway()) { // Do stuff here }

    Would the Dispose method be automatically called when execution reaches the end of the using block, or does the client have to manually call the dispose method?当执行到 using 块的末尾时会自动调用 Dispose 方法,还是客户端必须手动调用 dispose 方法? ie IE

     NoGateway objNoGateway = new NoGateway(); // Do stuff with object objNoGateway.Dispose(); // finished with it
  2. I am using the WebClient class in my NoGateway class.我在我的NoGateway类中使用WebClient类。 Because WebClient implements the IDisposable interface, does this mean that WebClient indirectly uses unmanaged resources?因为WebClient实现了IDisposable接口,这是否意味着WebClient间接使用了非托管资源? Is there a hard and fast rule to follow this?是否有严格的规则来遵循这一点? How do I know that a class uses unmanaged resources?我怎么知道一个类使用了非托管资源?

The recommended IDisposable pattern is here .推荐的 IDisposable 模式在这里 When programming a class that uses IDisposable, generally you should use two patterns:在编写使用 IDisposable 的类时,通常应使用两种模式:

When implementing a sealed class that doesn't use unmanaged resources, you simply implement a Dispose method as with normal interface implementations:在实现不使用非托管资源的密封类时,您只需像普通接口实现一样实现 Dispose 方法:

public sealed class A : IDisposable
{
    public void Dispose()
    {
        // get rid of managed resources, call Dispose on member variables...
    }
}

When implementing an unsealed class, do it like this:在实现未密封的类时,请这样做:

public class B : IDisposable
{    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // get rid of managed resources
        }   
        // get rid of unmanaged resources
    }

    // only if you use unmanaged resources directly in B
    //~B()
    //{
    //    Dispose(false);
    //}
}

Notice that I haven't declared a finalizer in B ;请注意,我没有在B声明终结器; you should only implement a finalizer if you have actual unmanaged resources to dispose.如果您有实际的非托管资源要处理,您应该只实现终结器。 The CLR deals with finalizable objects differently to non-finalizable objects, even if SuppressFinalize is called.即使调用了SuppressFinalize ,CLR 处理可终结对象的方式也不同于不可终结对象。

So, you shouldn't declare a finalizer unless you have to, but you give inheritors of your class a hook to call your Dispose and implement a finalizer themselves if they use unmanaged resources directly:因此,除非必须,否则不应声明终结器,但是如果类的继承者直接使用非托管资源,则为它们提供一个钩子以调用Dispose并自己实现终结器:

public class C : B
{
    private IntPtr m_Handle;

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            // get rid of managed resources
        }
        ReleaseHandle(m_Handle);

        base.Dispose(disposing);
    }

    ~C() {
        Dispose(false);
    }
}

If you're not using unmanaged resources directly ( SafeHandle and friends doesn't count, as they declare their own finalizers), then don't implement a finalizer, as the GC deals with finalizable classes differently, even if you later suppress the finalizer.如果您不直接使用非托管资源( SafeHandle和朋友不计算在内,因为它们声明了自己的终结器),则不要实现终结器,因为 GC 处理可终结类的方式不同,即使您稍后取消了终结器. Also note that, even though B doesn't have a finalizer, it still calls SuppressFinalize to correctly deal with any subclasses that do implement a finalizer.另请注意,即使B没有终结器,它仍会调用SuppressFinalize以正确处理任何实现终结器的子类。

When a class implements the IDisposable interface, it means that somewhere there are some unmanaged resources that should be got rid of when you've finished using the class.当一个类实现 IDisposable 接口时,这意味着在您使用完该类后,应该删除某些非托管资源。 The actual resources are encapsulated within the classes;实际资源被封装在类中; you don't need to explicitly delete them.您不需要明确删除它们。 Simply calling Dispose() or wrapping the class in a using(...) {} will make sure any unmanaged resources are got rid of as necessary.只需调用Dispose()或将类包装在using(...) {}确保根据需要删除任何非托管资源。

The official pattern to implement IDisposable is hard to understand.实现IDisposable的官方模式很难理解。 I believe this one is better :我相信这个更好

public class BetterDisposableClass : IDisposable {

  public void Dispose() {
    CleanUpManagedResources();
    CleanUpNativeResources();
    GC.SuppressFinalize(this);
  }

  protected virtual void CleanUpManagedResources() { 
    // ...
  }
  protected virtual void CleanUpNativeResources() {
    // ...
  }

  ~BetterDisposableClass() {
    CleanUpNativeResources();
  }

}

An even better solution is to have a rule that you always have to create a wrapper class for any unmanaged resource that you need to handle:一个更好的解决方案是制定一个规则,即您必须始终为需要处理的任何非托管资源创建包装类:

public class NativeDisposable : IDisposable {

  public void Dispose() {
    CleanUpNativeResource();
    GC.SuppressFinalize(this);
  }

  protected virtual void CleanUpNativeResource() {
    // ...
  }

  ~NativeDisposable() {
    CleanUpNativeResource();
  }

}

With SafeHandle and its derivatives, these classes should be very rare .使用SafeHandle及其派生类,这些类应该很少见

The result for disposable classes that don't deal directly with unmanaged resources, even in the presence of inheritance, is powerful: they don't need to be concerned with unmanaged resources anymore .即使存在继承,也不直接处理非托管资源的一次性类的结果是强大的:它们不再需要关注非托管资源 They'll be simple to implement and to understand:它们将很容易实现和理解:

public class ManagedDisposable : IDisposable {

  public virtual void Dispose() {
    // dispose of managed resources
  }

}

Note that any IDisposable implementation should follow the below pattern (IMHO).请注意,任何 IDisposable 实现都应遵循以下模式(恕我直言)。 I developed this pattern based on info from several excellent .NET "gods" the .NET Framework Design Guidelines (note that MSDN does not follow this for some reason!).我根据几个优秀的 .NET“神”的信息开发了这个模式.NET 框架设计指南(注意 MSDN 由于某种原因没有遵循这个!)。 The .NET Framework Design Guidelines were written by Krzysztof Cwalina (CLR Architect at the time) and Brad Abrams (I believe the CLR Program Manager at the time) and Bill Wagner ([Effective C#] and [More Effective C#] (just take a look for these on Amazon.com: .NET Framework 设计指南是由 Krzysztof Cwalina(当时的 CLR 架构师)和 Brad Abrams(我相信当时的 CLR 程序经理)和 Bill Wagner([Effective C#] 和 [More Effective C#](只需看看在 Amazon.com 上查找这些:

Note that you should NEVER implement a Finalizer unless your class directly contains (not inherits) UNmanaged resources.请注意,除非您的类直接包含(而不是继承)非托管资源,否则您永远不应该实现终结器。 Once you implement a Finalizer in a class, even if it is never called, it is guaranteed to live for an extra collection.一旦你在一个类中实现了一个 Finalizer,即使它从未被调用过,它也可以保证为一个额外的集合而存在。 It is automatically placed on the Finalization Queue (which runs on a single thread).它会自动放置在 Finalization Queue(在单个线程上运行)上。 Also, one very important note...all code executed within a Finalizer (should you need to implement one) MUST be thread-safe AND exception-safe!另外,一个非常重要的注意事项......在终结器中执行的所有代码(如果你需要实现一个)必须是线程安全的和异常安全的! BAD things will happen otherwise...(ie undetermined behavior and in the case of an exception, a fatal unrecoverable application crash).否则会发生糟糕的事情......(即未确定的行为,在异常情况下,致命的不可恢复的应用程序崩溃)。

The pattern I've put together (and written a code snippet for) follows:我整理的模式(并为其编写了代码片段)如下:

#region IDisposable implementation

//TODO remember to make this class inherit from IDisposable -> $className$ : IDisposable

// Default initialization for a bool is 'false'
private bool IsDisposed { get; set; }

/// <summary>
/// Implementation of Dispose according to .NET Framework Design Guidelines.
/// </summary>
/// <remarks>Do not make this method virtual.
/// A derived class should not be able to override this method.
/// </remarks>
public void Dispose()
{
    Dispose( true );

    // This object will be cleaned up by the Dispose method.
    // Therefore, you should call GC.SupressFinalize to
    // take this object off the finalization queue 
    // and prevent finalization code for this object
    // from executing a second time.

    // Always use SuppressFinalize() in case a subclass
    // of this type implements a finalizer.
    GC.SuppressFinalize( this );
}

/// <summary>
/// Overloaded Implementation of Dispose.
/// </summary>
/// <param name="isDisposing"></param>
/// <remarks>
/// <para><list type="bulleted">Dispose(bool isDisposing) executes in two distinct scenarios.
/// <item>If <paramref name="isDisposing"/> equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.</item>
/// <item>If <paramref name="isDisposing"/> equals false, the method has been called by the 
/// runtime from inside the finalizer and you should not reference 
/// other objects. Only unmanaged resources can be disposed.</item></list></para>
/// </remarks>
protected virtual void Dispose( bool isDisposing )
{
    // TODO If you need thread safety, use a lock around these 
    // operations, as well as in your methods that use the resource.
    try
    {
        if( !this.IsDisposed )
        {
            if( isDisposing )
            {
                // TODO Release all managed resources here

                $end$
            }

            // TODO Release all unmanaged resources here



            // TODO explicitly set root references to null to expressly tell the GarbageCollector
            // that the resources have been disposed of and its ok to release the memory allocated for them.


        }
    }
    finally
    {
        // explicitly call the base class Dispose implementation
        base.Dispose( isDisposing );

        this.IsDisposed = true;
    }
}

//TODO Uncomment this code if this class will contain members which are UNmanaged
// 
///// <summary>Finalizer for $className$</summary>
///// <remarks>This finalizer will run only if the Dispose method does not get called.
///// It gives your base class the opportunity to finalize.
///// DO NOT provide finalizers in types derived from this class.
///// All code executed within a Finalizer MUST be thread-safe!</remarks>
//  ~$className$()
//  {
//     Dispose( false );
//  }
#endregion IDisposable implementation

Here is the code for implementing IDisposable in a derived class.下面是在派生类中实现 IDisposable 的代码。 Note that you do not need to explicitly list inheritance from IDisposable in the definition of the derived class.请注意,您不需要在派生类的定义中显式列出从 IDisposable 的继承。

public DerivedClass : BaseClass, IDisposable (remove the IDisposable because it is inherited from BaseClass)


protected override void Dispose( bool isDisposing )
{
    try
    {
        if ( !this.IsDisposed )
        {
            if ( isDisposing )
            {
                // Release all managed resources here

            }
        }
    }
    finally
    {
        // explicitly call the base class Dispose implementation
        base.Dispose( isDisposing );
    }
}

I've posted this implementation on my blog at: How to Properly Implement the Dispose Pattern我已经在我的博客上发布了这个实现: 如何正确实现处置模式

I agree with pm100 (and should have explicitly said this in my earlier post).我同意pm100 (并且应该在我之前的帖子中明确说明这一点)。

You should never implement IDisposable in a class unless you need it.除非需要,否则永远不应该在类中实现 IDisposable。 To be very specific, there are about 5 times when you would ever need/should implement IDisposable:具体地说,大约有 5 次您需要/应该实现 IDisposable:

  1. Your class explicitly contains (ie not via inheritance) any managed resources which implement IDisposable and should be cleaned up once your class is no longer used.您的类明确包含(即不通过继承)任何实现 IDisposable 的托管资源,一旦您的类不再使用,就应该清除它们。 For example, if your class contains an instance of a Stream, DbCommand, DataTable, etc.例如,如果您的类包含 Stream、DbCommand、DataTable 等的实例。

  2. Your class explicitly contains any managed resources which implement a Close() method - eg IDataReader, IDbConnection, etc. Note that some of these classes do implement IDisposable by having Dispose() as well as a Close() method.您的类明确包含实现 Close() 方法的任何托管资源 - 例如 IDataReader、IDbConnection 等。请注意,其中一些类确实通过具有 Dispose() 和 Close() 方法实现了 IDisposable。

  3. Your class explicitly contains an unmanaged resource - eg a COM object, pointers (yes, you can use pointers in managed C# but they must be declared in 'unsafe' blocks, etc. In the case of unmanaged resources, you should also make sure to call System.Runtime.InteropServices.Marshal.ReleaseComObject() on the RCW. Even though the RCW is, in theory, a managed wrapper, there is still reference counting going on under the covers.您的类显式包含非托管资源 - 例如 COM 对象、指针(是的,您可以在托管 C# 中使用指针,但它们必须在“不安全”块等中声明。在非托管资源的情况下,您还应该确保在 RCW 上调用 System.Runtime.InteropServices.Marshal.ReleaseComObject()。尽管 RCW 理论上是一个托管包装器,但在幕后仍然存在引用计数。

  4. If your class subscribes to events using strong references.如果您的班级使用强引用订阅事件。 You need to unregister/detach yourself from the events.您需要从事件中注销/分离自己。 Always to make sure these are not null first before trying to unregister/detach them!.在尝试取消注册/分离它们之前,请务必先确保这些不为空!

  5. Your class contains any combination of the above...您的课程包含上述内容的任意组合...

A recommended alternative to working with COM objects and having to use Marshal.ReleaseComObject() is to use the System.Runtime.InteropServices.SafeHandle class.使用 COM 对象并必须使用 Marshal.ReleaseComObject() 的推荐替代方法是使用 System.Runtime.InteropServices.SafeHandle 类。

The BCL (Base Class Library Team) has a good blog post about it here http://blogs.msdn.com/bclteam/archive/2005/03/16/396900.aspx BCL(基类库团队)在这里有一篇很好的博客文章http://blogs.msdn.com/bclteam/archive/2005/03/16/396900.aspx

One very important note to make is that if you are working with WCF and cleaning up resources, you should ALMOST ALWAYS avoid the 'using' block.一个非常重要的注意事项是,如果您正在使用 WCF 并清理资源,您应该几乎总是避免使用 'using' 块。 There are plenty of blog posts out there and some on MSDN about why this is a bad idea.有很多博客文章和 MSDN 上的一些关于为什么这是一个坏主意的文章。 I have also posted about it here - Don't use 'using()' with a WCF proxy我也在这里发布了它 - 不要在 WCF 代理中使用“using()”

Using lambdas instead of IDisposable.使用 lambdas 而不是 IDisposable。

I have never been thrilled with the whole using/IDisposable idea.我从来没有对整个 using/IDisposable 的想法感到兴奋。 The problem is that it requires the caller to:问题是它要求调用者:

  • know that they must use IDisposable知道他们必须使用 IDisposable
  • remember to use 'using'.记住使用“使用”。

My new preferred method is to use a factory method and a lambda instead我的新首选方法是使用工厂方法和 lambda

Imagine I want to do something with a SqlConnection (something that should be wrapped in a using).想象一下,我想用 SqlConnection 做一些事情(应该用 using 包装的东西)。 Classically you would do传统上你会做

using (Var conn = Factory.MakeConnection())
{
     conn.Query(....);
}

New way新方法

Factory.DoWithConnection((conn)=>
{
    conn.Query(...);
}

In the first case the caller could simply not use the using syntax.在第一种情况下,调用者不能简单地使用 using 语法。 IN the second case the user has no choice.在第二种情况下,用户别无选择。 There is no method that creates a SqlConnection object, the caller must invoke DoWithConnection.没有创建 SqlConnection 对象的方法,调用者必须调用 DoWithConnection。

DoWithConnection looks like this DoWithConnection 看起来像这样

void DoWithConnection(Action<SqlConnection> action)
{
   using (var conn = MakeConnection())
   {
       action(conn);
   }
}

MakeConnection is now private MakeConnection现在是私有的

nobody answered the question about whether you should implement IDisposable even though you dont need it.没有人回答关于是否应该实施 IDisposable 的问题,即使您不需要它。

Short answer : No简短回答:否

Long answer:长答案:

This would allow a consumer of your class to use 'using'.这将允许您班级的消费者使用“使用”。 The question I would ask is - why would they do it?我想问的问题是——他们为什么要这样做? Most devs will not use 'using' unless they know that they must - and how do they know.大多数开发人员不会使用“使用”,除非他们知道必须使用 - 以及他们是如何知道的。 Either任何一个

  • its obviuos the them from experience (a socket class for example)从经验中可以看出它们(例如套接字类)
  • its documented其有据可查
  • they are cautious and can see that the class implements IDisposable他们很谨慎,可以看到该类实现了 IDisposable

So by implementing IDisposable you are telling devs (at least some) that this class wraps up something that must be released.因此,通过实现 IDisposable,您是在告诉开发人员(至少一些)这个类包含了一些必须发布的东西。 They will use 'using' - but there are other cases where using is not possible (the scope of object is not local);他们将使用 'using' - 但在其他情况下使用是不可能的(对象的范围不是本地的); and they will have to start worrying about the lifetime of the objects in those other cases - I would worry for sure.在其他情况下,他们将不得不开始担心对象的生命周期——我肯定会担心。 But this is not necessary但这不是必须的

You implement Idisposable to enable them to use using, but they wont use using unless you tell them to.您实施 Idisposable 以使他们能够使用 using,但除非您告诉他们,否则他们不会使用 using。

So dont do it所以不要这样做

Dispose pattern:配置模式:

public abstract class DisposableObject : IDisposable
{
    public bool Disposed { get; private set;}      

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~DisposableObject()
    {
        Dispose(false);
    }

    private void Dispose(bool disposing)
    {
        if (!Disposed)
        {
            if (disposing)
            {
                DisposeManagedResources();
            }

            DisposeUnmanagedResources();
            Disposed = true;
        }
    }

    protected virtual void DisposeManagedResources() { }
    protected virtual void DisposeUnmanagedResources() { }
}

Example of inheritance:继承的例子:

public class A : DisposableObject
{
    public Component components_a { get; set; }
    private IntPtr handle_a;

    protected override void DisposeManagedResources()
    {
        try
        {
          Console.WriteLine("A_DisposeManagedResources");
          components_a.Dispose();
          components_a = null;
        }
        finally
        { 
          base.DisposeManagedResources();
        }
    }

    protected override void DisposeUnmanagedResources()
    {
        try
        {
          Console.WriteLine("A_DisposeUnmanagedResources");
          CloseHandle(handle_a);
          handle_a = IntPtr.Zero;
        }
        finally
        { 
          base.DisposeUnmanagedResources();
        }
    }
}

public class B : A
{
    public Component components_b { get; set; }
    private IntPtr handle_b;

    protected override void DisposeManagedResources()
    {
        try
        {
          Console.WriteLine("B_DisposeManagedResources");
          components_b.Dispose();
          components_b = null;
        }
        finally
        { 
          base.DisposeManagedResources();
        }
    }

    protected override void DisposeUnmanagedResources()
    {
        try
        {
          Console.WriteLine("B_DisposeUnmanagedResources");
          CloseHandle(handle_b);
          handle_b = IntPtr.Zero;
        }
        finally
        { 
          base.DisposeUnmanagedResources();
        }
    }
}

Some aspects of another answer are slightly incorrect for 2 reasons:由于两个原因,另一个答案的某些方面略有不正确:

First,第一的,

using(NoGateway objNoGateway = new NoGateway())

actually is equivalent to:实际上相当于:

try
{
    NoGateway = new NoGateway();
}
finally
{
    if(NoGateway != null)
    {
        NoGateway.Dispose();
    }
}

This may sound ridiculous since the 'new' operator should never return 'null' unless you have an OutOfMemory exception.这听起来可能很荒谬,因为除非出现 OutOfMemory 异常,否则 'new' 运算符永远不应该返回 'null'。 But consider the following cases: 1. You call a FactoryClass that returns an IDisposable resource or 2. If you have a type that may or may not inherit from IDisposable depending on its implementation - remember that I've seen the IDisposable pattern implemented incorrectly many times at many clients where developers just add a Dispose() method without inheriting from IDisposable (bad, bad, bad).但请考虑以下情况: 1. 您调用返回 IDisposable 资源的 FactoryClass 或 2. 如果您的类型可能会或可能不会从 IDisposable 继承,具体取决于其实现 - 请记住,我已经看到 IDisposable 模式被错误地实现了很多有时在许多客户端,开发人员只是添加一个 Dispose() 方法而不从 IDisposable 继承(坏,坏,坏)。 You could also have the case of an IDisposable resource being returned from a property or method (again bad, bad, bad - don't 'give away your IDisposable resources)您还可能遇到从属性或方法返回 IDisposable 资源的情况(再次糟糕,糟糕,糟糕 - 不要“放弃您的 IDisposable 资源”)

using(IDisposable objNoGateway = new NoGateway() as IDisposable)
{
    if (NoGateway != null)
    {
        ...

If the 'as' operator returns null (or property or method returning the resource), and your code in the 'using' block protects against 'null', your code will not blow up when trying to call Dispose on a null object because of the 'built-in' null check.如果“as”运算符返回 null(或返回资源的属性或方法),并且“using”块中的代码防止“null”,则在尝试对 null 对象调用 Dispose 时,您的代码不会因为以下原因而崩溃“内置”空检查。

The second reason your reply is not accurate is because of the following stmt:你的回复不准确的第二个原因是因为下面的stmt:

A finalizer is called upon the GC destroying your object在 GC 销毁您的对象时调用终结器

First, Finalization (as well as GC itself) is non-deterministic.首先,Finalization(以及 GC 本身)是不确定的。 THe CLR determines when it will call a finalizer. CLR 确定何时调用终结器。 ie the developer/code has no idea.即开发人员/代码不知道。 If the IDisposable pattern is implemented correctly (as I've posted above) and GC.SuppressFinalize() has been called, the the Finalizer will NOT be called.如果正确实现了 IDisposable 模式(正如我在上面发布的那样)并且 GC.SuppressFinalize() 已被调用,则不会调用终结器。 This is one of the big reasons to properly implement the pattern correctly.这是正确实施模式的重要原因之一。 Since there is only 1 Finalizer thread per managed process, regardless of the number of logical processors, you can easily degrade performance by backing up or even hanging the Finalizer thread by forgetting to call GC.SuppressFinalize().由于每个托管进程只有 1 个 Finalizer 线程,无论逻辑处理器的数量如何,您都可以通过备份甚至通过忘记调用 GC.SuppressFinalize() 挂起 Finalizer 线程来轻松降低性能。

I've posted a correct implementation of the Dispose Pattern on my blog: How to Properly Implement the Dispose Pattern我在我的博客上发布了一个正确的处置模式实现如何正确实现处置模式

  1. If you are using other managed objects that are using unmanaged resources, it is not your responsibility to ensure those are finalized.如果您正在使用使用非托管资源的其他托管对象,则您没有责任确保这些资源已完成。 Your responsibility is to call Dispose on those objects when Dispose is called on your object, and it stops there.您的责任是在对您的对象调用 Dispose 时对这些对象调用 Dispose,并在那里停止。

  2. If your class doesn't use any scarce resources, I fail to see why you would make your class implement IDisposable.如果您的班级不使用任何稀缺资源,我不明白您为什么要让您的班级实现 IDisposable。 You should only do so if you're:您应该只在以下情况下这样做:

    • Know you will have scarce resources in your objects soon, just not now (and I mean that as in "we're still developing, it will be here before we're done", not as in "I think we'll need this")知道你的对象很快就会有稀缺资源,只是不是现在(我的意思是“我们仍在开发,它会在我们完成之前就在这里”,而不是“我认为我们需要这个”)
    • Using scarce resources使用稀缺资源
  3. Yes, the code that uses your code must call the Dispose method of your object.是的,使用您的代码的代码必须调用您的对象的 Dispose 方法。 And yes, the code that uses your object can use using as you've shown.是的,使用您的对象的代码可以如您所示使用using

  4. (2 again?) It is likely that the WebClient uses either unmanaged resources, or other managed resources that implement IDisposable. (又是 2 次?)WebClient 很可能使用非托管资源或其他实现 IDisposable 的托管资源。 The exact reason, however, is not important.然而,确切的原因并不重要。 What is important is that it implements IDisposable, and so it falls on you to act upon that knowledge by disposing of the object when you're done with it, even if it turns out WebClient uses no other resources at all.重要的是它实现了 IDisposable,因此当您处理完对象时,您需要根据该知识采取行动,即使事实证明 WebClient 根本不使用其他资源。

Pattern from msdn来自 msdn 的模式

public class BaseResource: IDisposable
{
   private IntPtr handle;
   private Component Components;
   private bool disposed = false;
   public BaseResource()
   {
   }
   public void Dispose()
   {
      Dispose(true);      
      GC.SuppressFinalize(this);
   }
   protected virtual void Dispose(bool disposing)
   {
      if(!this.disposed)
      {        
         if(disposing)
         {
            Components.Dispose();
         }         
         CloseHandle(handle);
         handle = IntPtr.Zero;
       }
      disposed = true;         
   }
   ~BaseResource()      
   {      Dispose(false);
   }
   public void DoSomething()
   {
      if(this.disposed)
      {
         throw new ObjectDisposedException();
      }
   }
}
public class MyResourceWrapper: BaseResource
{
   private ManagedResource addedManaged;
   private NativeResource addedNative;
   private bool disposed = false;
   public MyResourceWrapper()
   {
   }
   protected override void Dispose(bool disposing)
   {
      if(!this.disposed)
      {
         try
         {
            if(disposing)
            {             
               addedManaged.Dispose();         
            }
            CloseHandle(addedNative);
            this.disposed = true;
         }
         finally
         {
            base.Dispose(disposing);
         }
      }
   }
}

1) WebClient is a managed type, so you don't need a finalizer. 1) WebClient 是托管类型,因此您不需要终结器。 The finalizer is needed in the case your users don't Dispose() of your NoGateway class and the native type (which is not collected by the GC) needs to be cleaned up after.如果您的用户不使用您的 NoGateway 类的 Dispose() 并且需要在之后清理本机类型(未由 GC 收集),则需要终结器。 In this case, if the user doesn't call Dispose(), the contained WebClient will be disposed by the GC right after the NoGateway does.在这种情况下,如果用户不调用 Dispose(),则包含的 WebClient 将在 NoGateway 调用后立即由 GC 处理。

2) Indirectly yes, but you shouldn't have to worry about it. 2)间接是的,但您不必担心。 Your code is correct as stands and you cannot prevent your users from forgetting to Dispose() very easily.你的代码是正确的,你不能防止你的用户很容易忘记 Dispose()。

using(NoGateway objNoGateway = new NoGateway())

is equivalent to相当于

try
{
    NoGateway = new NoGateway();
}

finally
{
    NoGateway.Dispose();
}

A finalizer is called upon the GC destroying your object.在 GC 销毁您的对象时调用终结器。 This can be at a totally different time than when you leave your method.这可能与您离开方法的时间完全不同。 The Dispose of IDisposable is called immediately after you leave the using block.在您离开 using 块后立即调用 IDisposable 的 Dispose。 Hence the pattern is usually to use using to free ressources immediately after you don't need them anymore.因此,该模式通常用于在您不再需要资源后立即使用 using 来释放资源。

From what I know, it's highly recommended NOT to use the Finalizer / Destructor:据我所知,强烈建议不要使用终结器/析构函数:

public ~MyClass() {
  //dont use this
}

Mostly, this is due to not knowing when or IF it will be called.大多数情况下,这是由于不知道何时或是否会调用它。 The dispose method is much better, especially if you us using or dispose directly. dispose 方法要好得多,特别是如果您直接使用或 dispose。

using is good.使用是好的。 use it :)用它 :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM