I am a recent fanboy of AOP (aspect oriented) design patterns, so maybe this isn't anything new to you, but MAN it's changed my life. Staying hard-and-fast on the "DRY" principle (don't repeat yourself) is an awesome concept, but it isn't always easy. Take for instance the "Try/Catch/Finally" block. When accessing external resources, you sometimes need to wrap each call in a this block to manage the resource in the event of a failure. Something like, the following:
public void DoSomething()
{
try
{
// Perform the action
_service.Do();
}
catch (Exception exc)
{
// Log exception, etc.
Log(exc);
_service.Abort();
}
finally
{
// Clean up resources
_service.Close();
}
}
Now it isn't terribly obvious how you can get around this (at least it wasn't for me). If only we could have every call to this service wrapped in the same try/catch/finally block... Enter the Action<T> delegate. With this guy, you can create a method within this class (or a base blass) that provides this block as a wrapper for your action. For instance:
private void Invoke(Action<IService> action)
{
try
{
// Perform the action
func(_service);
}
catch (Exception exc)
{
// Log exception, etc.
Log(exc);
}
finally
{
// Clean up resources
_service.Close();
}
}
Then, you could make your calls like through the "Invoke" method and everything would be wrapped in the common Try/Catch/Finally block. Check it out:
public void DoSomething()
{
Invoke(s=>
s.Do()
);
}
It's that easy! Now, if you are going to be returning values, then you may want to create an overload using the Func<> delegate, like this:
private TReturnType Invoke<TReturnType>(Func<IService, TReturnType> action)
{
try
{
// Perform the action
return func(_service);
}
catch (Exception exc)
{
// Log exception, etc.
Log(exc);
}
finally
{
// Clean up resources
_service.Close();
}
}
Then it could be used like so:
public string DoSomething()
{
return Invoke(s=>
s.Do()
);
}
As you can see, this kind of thinking could have a major impact on your code and increase your code's reusability.
Enjoy.