Here is the scenario:
I have an object called a Transaction
that needs to make sure that only one entity has permission to edit it at any given time.
In order to facilitate a long-lived lock, I have the class generating a token object that can be used to make the edits.
You would use it like this:
var transaction = new Transaction();
using (var tlock = transaction.Lock())
{
transaction.Update(data, tlock);
}
Now, I want the TransactionLock
class to implement IDisposable
so that its usage can be clear. But, I don't have any unmanaged resources to dispose. however, the TransctionLock object itself is a sort of "unmanaged resource" in the sense that the CLR doesn't know how to properly finalize it.
All of this would be fine and dandy, I would just use IDisposable
and be done with it.
However, my issue comes when I try to do this in the finalizer:
~TransactionLock()
{
this.Dispose(false);
}
I want the finalizer to release the transaction from the lock, if possible. How, in the finalizer, do I detect if the parent transaction (this.transaction
) has already been finalized?
Is there a better pattern I should be using?
Also, the Transaction
class itself needn't be disposable, because it doesn't maintain a reference to the lock, and doesn't care whether or not it is unlocked when it goes to the grave.
The Transaction class looks something like this:
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;
}
}
}
And the Dispose(bool)
code for the TransactionLock
:
private void Dispose(bool disposing)
{
if (disposing)
{
if (this.Transaction != null)
{
this.Transaction.Unlock(this);
this.Transaction = null;
}
}
}