Something I often used back in C++ was letting a class A handle a state entry and exit condition for another class B, via the A constructor and destructor, to make sure that if something in that scope threw an exception, then B would have a known state when the scope was exited. This isn’t pure RAII as far as the acronym goes, but it’s an established pattern nevertheless.
In C#, I often want to do
class FrobbleManager
{
...
private void FiddleTheFrobble()
{
this.Frobble.Unlock();
Foo(); // Can throw
this.Frobble.Fiddle(); // Can throw
Bar(); // Can throw
this.Frobble.Lock();
}
}
Which needs to be done like this
private void FiddleTheFrobble()
{
this.Frobble.Unlock();
try
{
Foo(); // Can throw
this.Frobble.Fiddle(); // Can throw
Bar(); // Can throw
}
finally
{
this.Frobble.Lock();
}
}
if I want to guarantee the Frobble state when FiddleTheFrobble returns. The code would be nicer with
private void FiddleTheFrobble()
{
using (var janitor = new FrobbleJanitor(this.Frobble))
{
Foo(); // Can throw
this.Frobble.Fiddle(); // Can throw
Bar(); // Can throw
}
}
where FrobbleJanitor looks roughly like
class FrobbleJanitor : IDisposable
{
private Frobble frobble;
public FrobbleJanitor(Frobble frobble)
{
this.frobble = frobble;
this.frobble.Unlock();
}
public void Dispose()
{
this.frobble.Lock();
}
}
And that’s how I want to do it. Now reality catches up, since what I want to use requires that the FrobbleJanitor is used with using. I could consider this a code review issue, but something is nagging me.
Question: Would the above be considered as abusive use of using and IDisposable?
I don’t think so, necessarily. IDisposable technically is meant to be used for things that have non-managed resources, but then the using directive is just a neat way of implementing a common pattern of
try .. finally { dispose }.A purist would argue ‘yes – it’s abusive’, and in the purist sense it is; but most of us do not code from a purist perspective, but from a semi-artistic one. Using the ‘using’ construct in this way is quite artistic indeed, in my opinion.
You should probably stick another interface on top of IDisposable to push it a bit further away, explaining to other developers why that interface implies IDisposable.
There are lots of other alternatives to doing this but, ultimately, I can’t think of any that will be as neat as this, so go for it!