Sometimes I need to use several disposable objects within a function. Most common case is having StreamReader and StreamWriter but sometimes it's even more than this.
Nested using statements quickly add up and look ugly. To remedy this I've created a small class that collects IDisposable objects and disposes of them when it itself is disposed.
public class MultiDispose : HashSet<IDisposable>, IDisposable
{
public MultiDispose(params IDisposable[] objectsToDispose)
{
foreach (IDisposable d in objectsToDispose)
{
this.Add(d);
}
}
public T Add<T>(T obj) where T : IDisposable
{
base.Add(obj);
return obj;
}
public void DisposeObject(IDisposable obj)
{
obj.Dispose();
base.Remove(obj);
}
#region IDisposable Members
public void Dispose()
{
foreach (IDisposable d in this)
{
d.Dispose();
}
}
#endregion
}
So my code now looks like this:
using (MultiDispose md = new MultiDispose())
{
StreamReader rdr = md.Add(new StreamReader(args[0]));
StreamWriter wrt = md.Add(new StreamWriter(args[1]));
WhateverElseNeedsDisposing w = md.Add(new WhateverElseNeedsDisposing());
// code
}
Is there anything wrong with this approach that can cause problems down the road? I left the Remove function inherited from the HashSet on purpose so that the class would be more flexible. Surely misusing this function can lead to objects not being disposed of properly, but then there many other ways to shoot yourself in the foot without this class.
The using statement causes the object itself to go out of scope as soon as Dispose is called. Within the using block, the object is read-only and can't be modified or reassigned. A variable declared with a using declaration is read-only.
In C#, the using keyword has two purposes: The first is the using directive, which is used to import namespaces at the top of a code file. The second is the using statement. C# 8 using statements ensure that classes that implement the IDisposable interface call their dispose method.
In C#, nesting of for, while, and do-while loops are allowed and you can also put any nested loop inside any other type of loop like in a for loop you are allowed to put nested if loop.
C# provides a special "using" statement to call Dispose method explicitly. using statement gives you a proper way to call the Dispose method on the object. In using statement, we instantiate an object in the statement. At the end of using statement block, it automatically calls the Dispose method.
You could just do this:
using (var a = new A())
using (var b = new B())
{
/// ...
}
A few points about the general principle:
using
statements without extra bracesIf you have two variables of the same type, you can use a single using statement:
using (Stream input = File.OpenRead("input.dat"),
output = File.OpenWrite("output.dat"))
{
}
Now assuming you really want to go ahead with this:
Add
.HashSet<T>
or indeed any collection. You should just have a list within the class as a private member variable.Dispose
calls fails, none of the other Dispose
calls will be made; with a traditional using
statement, each call to Dispose
is made within its own finally
block.Basically, I think it's a bad idea. Nesting two levels deep is far from painful; nesting three should be rare; nesting four or more strongly suggests refactoring. Rather than trying to cope with the pain of deep nesting, you should design away from it.
Maybe it is just that you have shown a simple example, but I think the following is more readable.
using (StreamReader rdr = new StreamReader(args[0]))
using (StreamWriter wrt = new StreamWriter(args[1]))
{
// code
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With