Dispose() 应该创建新的对象实例吗?

本文关键字:对象 实例 创建 Dispose | 更新日期: 2023-09-27 18:35:45

Using C#.NET 4.0

我公司的应用程序利用资源储物柜来防止记录同时被编辑。我们使用数据库来存储锁的开始时间以及获取锁的用户。这导致了以下(奇怪的?)资源保险箱上的 dispose 实现,它恰好是从析构函数调用的:

protected virtual void Dispose(bool disposing)
        {
            lock (this)
            {
                if (lockid.HasValue)
                {
                    this.RefreshDataButtonAction = null;
                    this.ReadOnlyButtonAction = null;
                try
                {
                    **Dictionary<string, object> parameters = new Dictionary<string, object>();
                    parameters.Add("@lockID", lockid.Value);
                    parameters.Add("@readsToDelete", null);
                    Object returnObject = dbio2.ExecuteScalar("usp_DeleteResourceLockReads", parameters);**
                    lockid = null;
                }
                catch (Exception ex)
                {
                    Logger.WriteError("ResourceLockingController", "DeleteResourceLocks", ex);
                }
                finally
                {
                    ((IDisposable)_staleResourcesForm).Dispose();
                    _staleResourcesForm = null;
                }
            }
        }
    }

我担心我们粗体部分,因为一直在记录数据库调用中奇怪的"句柄未初始化"异常。我在其他地方读到在 Finalize() 期间创建新对象是不安全的,但同样的规则适用于 dispose() 吗?在Dispose()期间创建新对象时是否有任何可能的副作用?

Dispose() 应该创建新的对象实例吗?

碰巧是从析构函数调用

这才是真正的问题。 不能假定 *dbio2" 对象本身尚未完成。 在 .NET 中,最终确定顺序不是确定性的。 结果看起来与您描述的非常相似,dbase 提供程序使用的内部句柄将被释放,因此预计会出现"句柄未初始化"异常。 或者 dbio2 对象只是已经释放了。

这在程序退出时尤其容易出错。 然后,当终结器线程的 2 秒超时时,您也会遇到问题,dbase 操作很容易花费更多时间。

您根本不能依靠终结器为您执行此操作。 您必须检查释放参数,而不是调用 dbio2。ExecuteScalar() 方法,当它为 false 时。 这可能也结束了析构函数的有用性。

Dispose只是一个方法,就像任何其他方法一样。 有一些关于它应该/不应该做的事情的约定,但从系统的角度来看,在Dispose调用中创建对象没有任何错误。

进行数据库调用对个人来说有点令人担忧;我不希望在Dispose方法中调用如此昂贵且容易出错的活动,但这更像是一种约定/期望。 系统不会有问题。

是的,但我不会这样做,除非创建的对象在方法的本地范围内。 IDisposable 是一个通告,表明此类具有某些资源(通常是非托管资源),当不再使用该对象时,应释放这些资源。 如果您的 Dispose 正在被您的 finializer 调用(即您不是直接调用析构函数,而是等待 GC 执行此操作),则可能表明您应该更早调用它。 你永远不知道 C# 析构函数何时运行,因此你可能会不必要地占用该资源。 这也可能表明您的类不需要实现 IDisposable。

在您的情况下,您正在使用对象 dbio2,我假设它代表您的数据库连接。 但是,由于这是从析构函数调用的,因此如何知道连接是否仍然有效? 您的析构函数可能会在连接丢失一小时后。您应该尝试确保在知道 dbio2 对象仍在范围内时调用此释放。