I've got some code that has an awful lot of duplication. The problem comes from the fact that I'm dealing with nested IDisposable
types. Today I have something that looks like:
public void UpdateFromXml(Guid innerId, XDocument someXml)
{
using (var a = SomeFactory.GetA(_uri))
using (var b = a.GetB(_id))
using (var c = b.GetC(innerId))
{
var cWrapper = new SomeWrapper(c);
cWrapper.Update(someXml);
}
}
public bool GetSomeValueById(Guid innerId)
{
using (var a = SomeFactory.GetA(_uri))
using (var b = a.GetB(_id))
using (var c = b.GetC(innerId))
{
return c.GetSomeValue();
}
}
The whole nested using
block is the same for each of these methods (two are shown, but there are about ten of them). The only thing that is different is what happens when you get to the inner level of the using
blocks.
One way I was thinking would be to do something along the lines of:
public void UpdateFromXml(Guid innerId, XDocument someXml)
{
ActOnC(innerId, c =>
{
var cWrapper = new SomeWrapper(c);
cWrapper.Update(someXml);
});
}
public bool GetSomeValueById(Guid innerId)
{
var result = null;
ActOnC(innerId, c => { result = c.GetSomeValue(); });
return result;
}
private void ActOnC(Guid innerId, Action<TheCType> action)
{
using (var a = SomeFactory.GetA(_uri))
using (var b = a.GetB(_id))
using (var c = b.GetC(innerId))
{
action(c);
}
}
This works, it's just kind of clunky to parse (as a human). Does anyone have any other suggestions on how one could reduce the code duplication around nested using
blocks like this? If they weren't IDisposable
then one would likely just create a method to return the results of b.GetC(innerId)
... but that isn't the case here.
I like the answer provided by BFree as a start, but I'd make a few modifications.
//Give it a better name; this isn't designed to be a general purpose class
public class MyCompositeDisposable : IDisposable
{
public MyCompositeDisposable (string uri, int id, int innerid)
{
A = SomeFactory.GetA(uri);
B = A.GetB(id);
C = B.GetC(innerId);
}
//You can make A & B private if appropriate;
//not sure if all three or just C should be exposed publicly.
//Class names are made up; you'll need to fix.
//They should also probably be given more meaningful names.
public ClassA A{get;private set;}
public ClassB B{get;private set;}
public ClassC C{get;private set;}
public void Dispose()
{
A.Dispose();
B.Dispose();
C.Dispose();
}
}
After doing that you can do something like:
public bool GetSomeValueById(Guid innerId)
{
using(MyCompositeDisposable d = new MyCompositeDisposable(_uri, _id, innerId))
{
return d.C.GetSomeValue();
}
}
Note that the MyCompositeDisposable will likely need to have try/finally blocks in the constructor and Dispose methods so that errors in creation/destruction properly ensure nothing ends up un-disposed.
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