Reputation: 193
I am creating a class, say LockHolder, to simplify the lock requiring logic. It implements the IDisposable interface, thus I can use it like this:
using(LockHolderCreater.Create(lockObject, waittime))
{
//do something
}
The Dispose method of LockHolder releases lockObject (through Monitor.Exit) if it has been gained (through Monitor.TryEnter). That works fine if I create a new LockHolder object everytime LockHolderCreater.Create is called, but that would create too many instances of LockHolder. So I Write LockHolderCreater to maintain a list of LockHolder objects in order to reuse them. Now I am facing too problems:
First, when debugging, I found there are many such message as "A first chance exception of type 'System.ObjectDisposedException' occurred in System.dll" in the output window. If what the "using" statement do is just to call the Dispose method, can I prevent this kind of exception?
Second, and more importantly, if I reuse the LockerHolder instances, at some early time after my application starts, a SynchronizationLockException exception would be thrown when I try to release a lock in the Dispose method, saying that "Object synchronization method was called from an unsynchronized block of code.". I checked my logic, but I don't think it is possible that one LockHolder instance would be used by two threads at the same time. Can this be related with the ObjectDisposedException noted above?
ABOUT the answer
I don't get a direct answer of my question, but Marc Gravell's answer has made it less neccessary.
Upvotes: 2
Views: 3703
Reputation: 1064004
Should you do it: probably not, except for very exceptional scenarios where you are in complete control of the types.
Can you do it: this depends entirely on the implementation - and you certainly wouldn't want to apply that at random to arbitrary types. If, however, the type is (as part of cleanup) returned to some pool and re-initialized and re-used, then yes it will work. But: you risk problems if the // do something
code leaked the reference somewhere.
can I prevent this kind of exception?
yes: don't access an object after you've disposed it
saying that "Object synchronization method was called from an unsynchronized block of code."
I wonder - are you perhaps using await
here? or an iterator block? or something like that? If the enter and exit code runs on different threads, it will fail.
If your intent here is to minimize allocations of LockerHolder
, there is a better approach: use a struct
:
using System;
struct Foo : IDisposable
{
public Foo(string msg)
{
Console.WriteLine("Init: " + msg);
}
public void Dispose()
{
Console.WriteLine("Disposed");
}
}
static class Program
{
static void Main()
{
Console.WriteLine("Before");
using (new Foo("Hi"))
{
Console.WriteLine("Do stuff");
}
Console.WriteLine("After");
}
}
The Main
method here compiles the Dispose
using constrained
-call, which means it doesn't box.
Note that for this to work, the LockHolderCreater.Create
method must return the struct itself - it cannot return just IDisposable
.
Upvotes: 4
Reputation: 161821
It is a bad idea to abuse the using
statement. It is not intended as a general-purpose "automatic undo". It is only intended as a means to ensure the disposal of unmanaged resources like database connections.
Upvotes: 1
Reputation: 550
Declaring the variable inside the using statement's control expression limits the scope of the variable to inside the using statement.
Check this answer
Upvotes: 0