patterncsharpMinor
Custom database Lock - implemented with IDisposable
Viewed 0 times
withimplementeddatabasecustomidisposablelock
Problem
I have a lock class, that handels a database lock. It's not important how.
It is used in the beginning of a large operation, here is how it is used today:
I would like to use it like this instead:
this works fine, but im not sure wether it is a bad idea. I have implemented IDisposable on my class
Here is how the class look:
Is this abuse of the IDisposable interface?
It is used in the beginning of a large operation, here is how it is used today:
public void LargeOperation()
{
try
{
MyLock.DoLock("SomeId");
// Do lots of stuff that might thorw exceptions
}
finally
{
MyLock.ReleaseLock("SomeId");
}
}I would like to use it like this instead:
public void LargeOperation()
{
using(new MyLock("someId"))
{
// Do lots of stuff that might thorw exceptions
}
}this works fine, but im not sure wether it is a bad idea. I have implemented IDisposable on my class
MyLock but it doesn't dispose.. instead it releases the lock. Here is how the class look:
public class MyLock : IDisposable
{
private string _id;
public MyLock(string id)
{
DoLock(id);
}
public static void DoLock(string id)
{
//..code omitted
}
public static void ReleaseLock(string id)
{
//..code omitted
}
public void Dispose()
{
ReleaseLock(_id);
}
}Is this abuse of the IDisposable interface?
Solution
The
I would not say that this is an abuse of the disposable pattern: You acquire a lock which is a resource and you need to release it at a given point in time. For me this is good enough especially since you said it's some kind of db lock which I assume lives outside of the application (that is unmanaged for me). It provides you with native support through
However I don't particularly like your two public static methods on there. Now you all of a sudden have two interfaces into the class. If you want a factory like interface then make the
While you could do without a public
Some things to consider:
IDisposable was primarily added in order to be able to release acquired unmanaged resources in a deterministic fashion. However it also provides a nice way of releasing other resources in a deterministic fashion as you have found.I would not say that this is an abuse of the disposable pattern: You acquire a lock which is a resource and you need to release it at a given point in time. For me this is good enough especially since you said it's some kind of db lock which I assume lives outside of the application (that is unmanaged for me). It provides you with native support through
using to make sure it's released in case the executing code throws an exception.However I don't particularly like your two public static methods on there. Now you all of a sudden have two interfaces into the class. If you want a factory like interface then make the
DoLock method a proper factory method returning the lock which was acquired (in which case the ctor should become private):public class MyLock : IDisposable
{
private string _id;
private MyLock(string id)
{
_id = id;
DoLock();
}
public static MyLock Acquire(string id)
{
return new MyLock(id);
}
private void DoLock()
{
// get the lock
}
public void Release()
{
// release it
}
public void Dispose()
{
Release();
}
}While you could do without a public
Release method having Dispose calling Release is semantically useful in case you can't use using and need to release the lock explicitly. In this case the code will be clearer when you call Release rather than Dispose. The .NET stream classes do a similar thing (where Dispose calls Close).Some things to consider:
- Add an "object is disposed" flag so you don't try to release the same lock twice.
- Add a finalizer to try and release the lock in case it was not properly released. Add a
Debug.Assertat least for that case. Note that adding a finalizer will make allMyLockobjects go through the finalizer queue which will add overhead for the GC. You could wrap the finalizer into a#ifdef DEBUGto only do that in debug builds - depends how many of these locks you create (although I guess if you create lots of them you have another problem altogether).
Code Snippets
public class MyLock : IDisposable
{
private string _id;
private MyLock(string id)
{
_id = id;
DoLock();
}
public static MyLock Acquire(string id)
{
return new MyLock(id);
}
private void DoLock()
{
// get the lock
}
public void Release()
{
// release it
}
public void Dispose()
{
Release();
}
}Context
StackExchange Code Review Q#33371, answer score: 5
Revisions (0)
No revisions yet.