安全调用从终结管理的资源? (如果我检查空) [英] Safe to call managed resource from Finalizer? (if i check null)

查看:153
本文介绍了安全调用从终结管理的资源? (如果我检查空)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这难道不是安全地调用:



component.Dispose(); (如果我检查空)



这是终结,如果我的代码改成这样:

 〜MyResource()
{
的Dispose();
}
公共无效的Dispose()
{
//检查处置是否已经调用。
如果(this.disposed!)
{
如果component.Dispose()(分量!= NULL); //! //

CloseHandle的(处理);
手柄= IntPtr.Zero;

处置= TRUE;

}
GC.SuppressFinalize(本);
}



我知道这工作 - 但它的安全?



(从下面的例子?)



代码示例:(前修改代码)



的http:// MSDN .microsoft.com / EN-US /库/ system.idisposable.dispose.aspx

 使用系统; 
使用System.ComponentModel;

//下面的例子演示了如何创建
//实现IDisposable接口
//和IDisposable.Dispose方法的资源类。

公共类DisposeExample
{
//实现了IDisposable的基类。
//通过实施了IDisposable,你宣布这一类型的
//实例分配稀缺资源。
公共类MyResource:IDisposable的
{
//指向外部非托管资源。
私人IntPtr的手柄;
//其他托管资源这个类使用。
私人色差分量=新组件();
//轨道处置是否已调用。
私人BOOL处置= FALSE;

//类构造函数。
公共MyResource(IntPtr的手柄)
{
this.handle =手柄;
}

//实现IDisposable。
//不要使用此法虚拟的。
//派生类不应该能够覆盖这个方法。
公共无效的Dispose()
{
的Dispose(真);
//这个对象将被Dispose方法来清理。
//所以,你应该叫GC.SupressFinalize至
//借此对象从终结队列
//并阻止该对象
终止代码//从执行第二次。
GC.SuppressFinalize(本);
}

//的Dispose(BOOL处置)执行两个不同的场景。
//如果处置等于true,该方法已被直接调用
//或间接地由用户的密码。托管和非托管资源
//可以配置。
//如果处置等于false,该方法已经从终结内部调用由
//运行时,你不应该引用
//其他对象。只有非托管资源可以被处理。
受保护的虚拟无效的Dispose(BOOL处置)
{
//检查处置是否已经调用。
如果(!this.disposed)
{
//如果处置等于true,处置所有托管
//和非托管资源。
如果(处置)
{
//处置管理的资源。
component.Dispose();
}

//调用适当的方法来清理
//非托管资源在这里。
//如果处置是假的,
//只执行下面的代码。
CloseHandle的(处理);
手柄= IntPtr.Zero;

//注意处置已经完成。
处置= TRUE;

}
}

//使用互操作调用该方法需要
//清理非托管资源。
[System.Runtime.InteropServices.DllImport(Kernel32中)]
私有外部静态布尔CloseHandle的(IntPtr的手柄);

//使用C#析构函数终止代码的语法。
//此析构函数将只运行,如果Dispose方法
//不会被调用。
//它给你的基类的机会来完成。
//不要提供从这个类派生类型的析构函数。
〜MyResource()
{
//不要再在这里创建处置清理代码。
//调用Dispose(假)是
//可读性和可维护性方面的优化。
的Dispose(假);
}
}
公共静态无效的主要()
{
//此处插入代码来创建
//并使用MyResource对象。
}
}


解决方案

这是很难确定它是否是安全的不知道'分量'的实施细节做。对象的终结是无序的,不尊重包容层次,因此,尽管组件实例可能不是,它可能已经被你打电话的时候<$敲定C $ C>的Dispose 就可以了。常的Dispose 方法不与该类型在充分考虑安全的书面因为他们只期望目标确定之前被调用。



之前,你甚至会想考虑做聪明的事情就像在抚摸终结其他对象,请阅读克里斯Brumme的博客关于这个问题的帖子; 这个人是一个很好的起点



一般情况下,除非是非常特殊的情况下,你知道,所含对象的的Dispose 方法的行为甚至有望当它已经完成调用的时候,我会假设你已经问格局是不是安全,并将与传递布尔处置参数,只触及的推荐模式粘管理的对象如果是真正


Is it not safe to call:

component.Dispose(); (if i check null)

from the Finalizer if i alter the code to this:

~MyResource()
{
    Dispose();
}
public void Dispose()
{
 // Check to see if Dispose has already been called.
        if(!this.disposed)
        {
            if(component != null) component.Dispose();   // !!! //

            CloseHandle(handle);
            handle = IntPtr.Zero;

            disposed = true;

        }
    GC.SuppressFinalize(this);
}

I know this works - but is it safe?

(from the example below?)

Code example: (before alter code)

http://msdn.microsoft.com/en-us/library/system.idisposable.dispose.aspx

using System;
using System.ComponentModel;

// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.

public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
    // Pointer to an external unmanaged resource.
    private IntPtr handle;
    // Other managed resource this class uses.
    private Component component = new Component();
    // Track whether Dispose has been called.
    private bool disposed = false;

    // The class constructor.
    public MyResource(IntPtr handle)
    {
        this.handle = handle;
    }

    // Implement IDisposable.
    // Do not make this method virtual.
    // A derived class should not be able to override this method.
    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.
        GC.SuppressFinalize(this);
    }

    // Dispose(bool disposing) executes in two distinct scenarios.
    // If disposing equals true, the method has been called directly
    // or indirectly by a user's code. Managed and unmanaged resources
    // can be disposed.
    // If disposing 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.
    protected virtual void Dispose(bool disposing)
    {
        // Check to see if Dispose has already been called.
        if(!this.disposed)
        {
            // If disposing equals true, dispose all managed
            // and unmanaged resources.
            if(disposing)
            {
                // Dispose managed resources.
                component.Dispose();
            }

            // Call the appropriate methods to clean up
            // unmanaged resources here.
            // If disposing is false,
            // only the following code is executed.
            CloseHandle(handle);
            handle = IntPtr.Zero;

            // Note disposing has been done.
            disposed = true;

        }
    }

    // Use interop to call the method necessary
    // to clean up the unmanaged resource.
    [System.Runtime.InteropServices.DllImport("Kernel32")]
    private extern static Boolean CloseHandle(IntPtr handle);

    // Use C# destructor syntax for finalization code.
    // This destructor will run only if the Dispose method
    // does not get called.
    // It gives your base class the opportunity to finalize.
    // Do not provide destructors in types derived from this class.
    ~MyResource()
    {
        // Do not re-create Dispose clean-up code here.
        // Calling Dispose(false) is optimal in terms of
        // readability and maintainability.
        Dispose(false);
    }
  }
  public static void Main()
  {
    // Insert code here to create
    // and use the MyResource object.
  }
}

解决方案

It's hard to determine whether it's safe to do without knowing the implementation details of 'component'. Finalization of objects is unordered and does not respect containment hierarchy, so while the 'component' instance may not be null, it may already have been finalized by the time you call Dispose on it. Often Dispose methods aren't written with that type of safety in mind because they only expect to be called before the object is finalized.

Before you'd even want to consider doing clever things like touching other objects in finalizers, read Chris Brumme's blog posts on the subject; this one is a good starting point.

Generally, except in very specific circumstances, and you know that the Dispose method of the contained object behaves as expected even when called when it has been finalized, I'd assume the pattern you have asked about is not safe and would stick with the recommended pattern of passing a bool disposing parameter and only touching managed objects if it is true.

这篇关于安全调用从终结管理的资源? (如果我检查空)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆