Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.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# IDisposable.Dispose()是否应该安全地多次调用?_C#_.net_Idisposable - Fatal编程技术网

C# IDisposable.Dispose()是否应该安全地多次调用?

C# IDisposable.Dispose()是否应该安全地多次调用?,c#,.net,idisposable,C#,.net,Idisposable,IDisposable的实现是否应该使Dispose()能够安全地多次调用?还是相反?大多数.NET Framework类都采用什么方法 具体来说,多次调用System.Data.Linq.DataContext.Dispose()安全吗 我之所以问这个问题,是因为我想知道这种额外的保护是否必要: public override void Dispose(bool disposing) { // Extra protection... if (this.obj != null)

IDisposable的实现是否应该使Dispose()能够安全地多次调用?还是相反?大多数.NET Framework类都采用什么方法

具体来说,多次调用
System.Data.Linq.DataContext.Dispose()
安全吗

我之所以问这个问题,是因为我想知道这种额外的保护是否必要:

public override void Dispose(bool disposing)
{
    // Extra protection...
    if (this.obj != null)
    {
        this.obj.Dispose();
        this.obj = null;
    }

    // Versus simply...
    this.obj.Dispose();

    base.Dispose(disposing);
}

在处理类的IDisposable成员时,或者我是否应该只调用
this.obj.Dispose()
,而不考虑以前是否调用过它。

您应该可以安全地多次调用它,尽管如果可以,您可能应该避免调用它

从上的MSDN页面:

如果对象的Dispose方法被多次调用,则该对象必须忽略第一次调用之后的所有调用。如果多次调用该对象的Dispose方法,则该对象不得引发异常


是的,IDisposable.Dispose()的实现应该允许多次调用。在第一次调用Dispose()之后,所有其他调用都可以立即返回

我更喜欢代码示例的第一部分,即在运行时处理局部变量并将其设为null


请注意,即使在代码中实现了Dispose和null模式,也可能会多次调用.Dispose()。如果多个使用者持有对同一个一次性对象的引用,则当这些使用者删除对该对象的引用时,该对象的Dispose可能会被调用多次。

如果某个对象已被释放,则不应再次处理该对象。这有助于您避免延长垃圾收集器中该对象的使用寿命

我通常使用的模式是这样的

// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class BaseClass: IDisposable
{
    /// <summary>
    /// A value indicating whether this instance of the given entity has 
    /// been disposed.
    /// </summary>
    /// <value>
    /// <see langword="true"/> if this instance has been disposed; otherwise, 
    /// <see langword="false"/>.
    /// </value>
    /// <remarks>
    /// If the entity is disposed, it must not be disposed a second
    /// time. The isDisposed field is set the first time the entity
    /// is disposed. If the isDisposed field is true, then the Dispose()
    /// method will not dispose again. This help not to prolong the entity's
    /// life in the Garbage Collector.
    /// </remarks>
    private bool isDisposed;

   /// <summary>
    /// Disposes the object and frees resources for the Garbage Collector.
    /// </summary>
    public void Dispose()
    {
        this.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);
    }

    /// <summary>
    /// Disposes the object and frees resources for the Garbage Collector.
    /// </summary>
    /// <param name="disposing">If true, the object gets disposed.</param>
    protected virtual void Dispose(bool disposing)
    {
        if (this.isDisposed)
        {
            return;
        }

        if (disposing)
        {
            // Dispose of any managed resources here.

        }

        // Call the appropriate methods to clean up
        // unmanaged resources here.
        // Note disposing is done.
        this.isDisposed = true;

    }

    // 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.
    ~BaseClass()
    {
        // Do not re-create Dispose clean-up code here.
        // Calling Dispose(false) is optimal in terms of
        // readability and maintainability.
        Dispose(false);
    }      
}
//实现IDisposable的基类。
//通过实现IDisposable,您宣布
//这种类型的实例分配稀缺资源。
公共类基类:IDisposable
{
/// 
///一个值,指示给定实体的此实例是否具有
///已经处理好了。
/// 
/// 
///如果已处理此实例,则为,
/// .
/// 
/// 
///如果该实体已被处置,则不得再次处置该实体
///时间。isDisposed字段是在第一次创建实体时设置的
///如果isDisposed字段为true,则Dispose()
///方法将不再处理。这有助于不延长实体的
///生活在垃圾收集器里。
/// 
私人住宅被出售;
/// 
///处置对象并释放垃圾收集器的资源。
/// 
公共空间处置()
{
这个。处置(真实);
//此对象将通过Dispose方法清除。
//因此,您应该调用GC.superssfalize来
//将此对象从终结队列中移除
//并阻止此对象的终结代码
//从第二次执行开始。
总干事(本);
}
/// 
///处置对象并释放垃圾收集器的资源。
/// 
///如果为true,则对象将被释放。
受保护的虚拟void Dispose(bool disposing)
{
如果(此.isDisposed)
{
返回;
}
如果(处置)
{
//在此处处置所有托管资源。
}
//调用适当的方法进行清理
//这里是非托管资源。
//注:处理完成。
this.isDisposed=true;
}
//使用C#析构函数语法完成代码。
//仅当Dispose方法
//没有人打电话。
//它为基类提供了最终确定的机会。
//不要在此类派生的类型中提供析构函数。
~BaseClass()
{
//不要在此处重新创建Dispose清理代码。
//调用Dispose(false)在以下方面是最佳的
//可读性和可维护性。
处置(虚假);
}      
}

对象应该允许多次调用Dispose,因为清理代码可能很难确定哪些内容已清理,哪些未清理,尤其是在存在异常的情况下。清除IDisposable字段时将其置零(并容忍已为null的字段)将更容易避免多余的Dispose调用,但使对象容忍多次处理实际上并不需要花费任何成本,而且在某些异常抛出情况下也有助于避免不适。

我更喜欢if(!=null)语法。还应使用disposing标志保护聚合对象的dispose。如果对象也有终结器,请确保仅在“disposing”为false时调用this.obj.dispose()。否则,您可能正在从终结器中访问另一个对象,该对象可能已经终结(终结顺序未定义,循环引用没有安全的终结顺序)。如果我是Microsoft,我会将“disposing”标志重命名为“disposedexplicity”或“notInFinalizer”:)第二次处理对象如何延长对象的生存期?垃圾收集器所关心的是是否还有对它的引用。此外,您编写的代码不必要地调用GC.SuppressFinalize(),声称该对象位于终结队列中,但它不在终结队列中,因为它没有终结器。GC不会以任何方式寻找IDisposable(这无论如何都是危险的,因为显式Dispose()可以访问其他对象上的方法,而终结器不应该这样做)。@Cycon:我意识到我没有在你的评论后发布足够完整的代码示例。我所说的延长生命是指它将持续存在于最终确定队列中。我已经更新添加了终结代码,并修复了我发现的另一个小错误。请注意,此模式只应在您实际处理非托管资源时使用,并且您的逻辑可以在不调用ReferenceCI的情况下执行