// AOP style advice using lambdas and simulated dynamic scoping. using System; public delegate void Target(); public interface Aspect { void advice(Target m); } public class aop1 { public static Func fun1 = (x)=>{return x.Length;}; public static Func fun2 = (x)=>Math.Sqrt(x); public static void RealMain() // the "real" main { Console.WriteLine(fun2( fun1("abcd") )); int y = fun1(null); double z = fun2(-1); Console.WriteLine(y+z); } public static void Main() // aspect weaver, not the "real" main { tracer tr = new tracer(); checker ck = new checker(); // run real main under advice, // innermost advice will have precedence (work like stack): tr.advice( ()=>ck.advice( ()=>RealMain() ) ); Console.WriteLine(fun2( fun1("abcd") )); // called outside of advice scope } }//aop1 main class //// classes that encapsulate cross-cutting aspects public class tracer : Aspect // traces fun1 and fun2 { public void advice(Target method) { // simulate dynamic scoping on function names Func storefun1 = aop1.fun1; Func storefun2 = aop1.fun2; // intercept calls to fun1: aop1.fun1 = (x)=> // simulate advice (better with reflection) { Console.WriteLine("starting call to fun1 with param "+x+" (string)"); int y = storefun1(x); // proceed Console.WriteLine("returning "+y+" from fun1"); return y; }; // intercept calls to fun2 aop1.fun2 = (x)=> { Console.WriteLine("starting call to fun2 with param "+x); double y = storefun2(x); // proceed Console.WriteLine("returning "+y+" from fun1"); return y; }; // dynamic bindings will apply to target method(); // the target method. // exit dynamic scope ("localize" effect of aspect class) aop1.fun1 = storefun1; aop1.fun2 = storefun2; }//trace }//tracer public class checker : Aspect // another aspect to check parameters { public void advice(Target method) { // simulate dynamic scoping on function names Func storefun1 = aop1.fun1; Func storefun2 = aop1.fun2; aop1.fun1 = (x)=> // simulate advice (better with reflection) { if (x==null) { Console.WriteLine("null string parameter to fun1 replaced with empty string"); x = ""; } return storefun1(x); }; aop1.fun2 = (x)=> { if (x<0) throw new Exception("negative parameter to sqrt"); else return storefun2(x); }; method(); // the target method. // exit dynamic scope aop1.fun1 = storefun1; aop1.fun2 = storefun2; }//trace }