Acabei de assistir essa palestra de Greg Young alertando as pessoas para o KISS: Keep It Simple Stupid.
Uma das coisas que ele sugeriu é que, para fazer uma programação orientada a aspectos, não é necessário um framework .
Ele começa fazendo uma forte restrição: que todos os métodos usem um, e apenas um, parâmetro (embora ele relaxe isso um pouco mais tarde usando aplicativo parcial ).
O exemplo que ele dá é definir uma interface:
public interface IConsumes<T>
{
void Consume(T message);
}
Se queremos emitir um comando:
public class Command
{
public string SomeInformation;
public int ID;
public override string ToString()
{
return ID + " : " + SomeInformation + Environment.NewLine;
}
}
O comando é implementado como:
public class CommandService : IConsumes<Command>
{
private IConsumes<Command> _next;
public CommandService(IConsumes<Command> cmd = null)
{
_next = cmd;
}
public void Consume(Command message)
{
Console.WriteLine("Command complete!");
if (_next != null)
_next.Consume(message);
}
}
Para fazer o logon no console, basta implementar:
public class Logger<T> : IConsumes<T>
{
private readonly IConsumes<T> _next;
public Logger(IConsumes<T> next)
{
_next = next;
}
public void Consume(T message)
{
Log(message);
if (_next != null)
_next.Consume(message);
}
private void Log(T message)
{
Console.WriteLine(message);
}
}
Em seguida, o log de pré-comando, serviço de comando e log de pós-comando são apenas:
var log1 = new Logger<Command>(null);
var svr = new CommandService(log);
var startOfChain = new Logger<Command>(svr);
e o comando é executado por:
var cmd = new Command();
startOfChain.Consume(cmd);
Para fazer isso, por exemplo, no PostSharp , é possível fazer anotações da CommandService
seguinte maneira:
public class CommandService : IConsumes<Command>
{
[Trace]
public void Consume(Command message)
{
Console.WriteLine("Command complete!");
}
}
E então tem que implementar o log em uma classe de atributo algo como:
[Serializable]
public class TraceAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args )
{
Console.WriteLine(args.Method.Name + " : Entered!" );
}
public override void OnSuccess( MethodExecutionArgs args )
{
Console.WriteLine(args.Method.Name + " : Exited!" );
}
public override void OnException( MethodExecutionArgs args )
{
Console.WriteLine(args.Method.Name + " : EX : " + args.Exception.Message );
}
}
O argumento que Greg usa é que a conexão do atributo com a implementação do atributo é "muita mágica" para poder explicar o que está acontecendo com um desenvolvedor júnior. O exemplo inicial é todo "apenas código" e facilmente explicado.
Então, após essa construção bastante demorada, a questão é: quando você muda da abordagem não-estrutural de Greg para usar algo como PostSharp para AOP?
IConsumes
partes diferentes . Em vez de ter que usar XML externo ou alguma interface Fluent - mais uma coisa a aprender. Alguém poderia argumentar que esta metodologia é "outra coisa a aprender" também.