我应该将IDisposable用于纯粹的托管资源吗?

时间:2010-04-05 20:08:10

标签: c# .net dispose idisposable

以下是该方案:

我有一个名为Transaction的对象,需要确保在任何给定时间只有一个实体有权编辑它。

为了方便长期锁定,我让类生成一个可用于进行编辑的令牌对象。

您可以这样使用它:

var transaction = new Transaction();

using (var tlock = transaction.Lock())
{
    transaction.Update(data, tlock);
}

现在,我希望TransactionLock类实现IDisposable,以便明确其用法。但是,我没有任何非托管资源可供处置。但是,TransctionLock对象本身就是一种“非托管资源”,因为CLR不知道如何正确地完成它。

所有这些都很好,花花公子,我只会使用IDisposable并完成它。

然而,当我尝试在终结器中执行此操作时,我的问题出现了:

~TransactionLock()
{
    this.Dispose(false);
}

如果可能的话,我希望终结器从锁中释放事务。 如何在终结器中检测父事务(this.transaction)是否已经完成?

我应该使用更好的模式吗?

此外,Transaction类本身不需要是一次性的,因为它不会保持对锁的引用,并且在它进入坟墓时不关心它是否被解锁。 / p>


Transaction类看起来像这样:

public sealed class Transaction
{
    private readonly object lockMutex = new object();

    private TransactionLock currentLock;

    public TransactionLock Lock()
    {
        lock (this.lockMutex)
        {
            if (this.currentLock != null)
                throw new InvalidOperationException(/* ... */);

            this.currentLock = new TransactionLock(this);
            return this.currentLock;
        }
    }

    public void Update(object data, TransactionLock tlock)
    {
        lock (this.lockMutex)
        {
            this.ValidateLock(tlock);

            // ...
        }
    }

    internal void ValidateLock(TransactionLock tlock)
    {
        if (this.currentLock == null)
            throw new InvalidOperationException(/* ... */);

        if (this.currentLock != tlock)
            throw new InvalidOperationException(/* ... */);
    }

    internal void Unlock(TransactionLock tlock)
    {
        lock (this.lockMutex)
        {
            this.ValidateLock(tlock);

            this.currentLock = null;
        }
    }
}

Dispose(bool)的{​​{1}}代码:

TransactionLock

2 个答案:

答案 0 :(得分:2)

这是discussed before。你的情况要容易得多,你也在实现终结者。这是根本错误的,你隐藏了客户端代码中的错误。请注意终结器在单独的线程上运行。调试一致的死锁比处理随机和异步消失的锁更容易。

建议:遵循.NET框架主角:不要太多帮助。出于同样的原因,Microsoft放弃了Synchronized方法。

答案 1 :(得分:1)

  

在终结器中,我如何检测是否   父交易   (this.transaction)已经存在   完成?

这可以通过在Transaction中保留_disposed布尔字段并通过IsDisposed只读属性公开它来实现。这是标准做法。

   ~TransactionLock()
    {
        this.Dispose(false);
    }
  

我应该有更好的模式吗?   使用

如果TransactionLock没有非托管资源是正确的,那么只需省略析构函数(终结器)。它没有功能,但确实有相当大的成本。

编辑:如果我读得正确,Unlock不会将事务从TransactionLock切换到TTransaction,这意味着将通过析构函数调用旧锁Dispose(bool)。目前尚不清楚这是否安全。

使用TransactionLock.Dispose(bool)

的代码,问题会更加完整
  

此外,Transaction类本身   不必是一次性的,因为它   没有保持对...的引用   锁定,并不关心是否   当它进入时它被解锁   严重。

由此可见,当收集TransactionLock时,它只能持有对也正在收集的Transaction的引用。这里不需要干扰析构函数,这不会解决任何问题,只会产生你不需要的问题。