I have a bunch of methods with varying signatures. These methods interact with a fragile data connection, so we often use a helper class to perform retries/reconnects, etc.
.NET Attributes are meta-data, not decorators / active components that automatically get invoked. There is no way to achieve this behaviour.
You could use attributes to implement decorators by putting the decorator code in the Attribute class and call the method with a helper method that invokes the method in the Attribute class using Reflection. But I'm not sure this would be a big improvement over just calling the "decorator-method" directly.
"Decorator-Attribute":
[AttributeUsage(AttributeTargets.Method)]
public class MyDecorator : Attribute
{
public void PerformCall(Action action)
{
// invoke action (or not)
}
}
Method:
[MyDecorator]
void MyMethod()
{
}
Usage:
InvokeWithDecorator(() => MyMethod());
Helper method:
void InvokeWithDecorator(Expression<Func<?>> expression)
{
// complicated stuff to look up attribute using reflection
}
Have a look at frameworks for Aspect Oriented Programming in C#. These may offer what you want.
This type of problem is pretty much what AOP (aspect oriented programming) aims to solve. Tools such as PostSharp can provide cross-cutting concerns by re-writing the compiled code. Scott Hanselman's podcast recently discussed AOP, so it might be worth having a listen.
Without the use of gode generation, you can't do much against it. You could probably make the syntax better.
But what about using an extension method?
class static MyHelper
{
Wrap<T>(this object service, Action<T> action)
{
// check attribute and wrap call
}
}
usage:
RawFoo foo = ...
foo.Wrap(x => x.doStuffWithData(parameters...));
This is trivial, but you can't make sure that Wrap had been used.
You could implement a generic decorator. This decorator would be used once to wrap the service and then you can't call it without wrapping.
class Decorator<T>
{
private T implementor;
Decorator(T implementor)
{
this.implementor = implementor;
}
void Perform<T>(Action<T> action)
{
// check attribute here to know if wrapping is needed
if (interactsWithData)
{
MyHelper.PerformCall( () => { action(implementor) });
}
else
{
action(implementor);
}
}
}
static class DecoratorExtensions
{
public static Decorator<T> CreateDecorator<T>(T service)
{
return new Decorator<T>(service);
}
}
Usage:
// after wrapping, it can't be used the wrong way anymore.
ExtendedFoo foo = rawFoo.CreateDecorator();
foo.Perform(x => x.doStuffWithData(parameters...));
Check out aspect oriented frameworks. But be aware that while they hide complexity in each method, the existence of AoP features could make your program harder to maintain. It's a tradeoff.
So, I just went to a AOP session this weekend, and here's a way to do it with PostSharp:
[Serializable]
public class MyAOPThing : MethodInterceptionAspect
{
public override void OnInvoke(MethodInterceptionArgs args)
{
Console.WriteLine("OnInvoke! before");
args.Proceed();
Console.WriteLine("OnInvoke! after");
}
}
And then decorate methods with [MyAOPThing]
. Easy!
Seeing that you're willing to add a line of code to every method that needs this, why not just make the call to MyHelper from within the method itself, like this?
protected string doStuffWithData(parameters...)
{
MyHelper.PerformCall( () => { doStuffWithDataCore(parameters...) });
}
private string doStuffWithDataCore(parameters...) {
//Do stuff here
}