b.logrythmik

{ independency injection }

In-Class AOP | Using Action<T> Delegates to Reduce Redundant Code

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.

blog comments powered by Disqus