четверг, 5 марта 2015 г.

PostSharp in Depth Part 1. How does my code look like?

Suppose you wrote some HelloWorldAspect and wondering: "How does my code look like?". I was wondering also. Let's look inside.

At first lets create some test project with simple aspect based derived from OnMethodBoundary aspect.

1:  using System;  
2:  using PostSharp.Aspects;  
3:  namespace HelloWorld  
4:  {  
5:    class Program  
6:    {  
7:      static void Main(string[] args)  
8:      {  
9:         Log(null);  
10:        Console.ReadLine();  
11:      }  
12:      [MyAspec]  
13:      private static void Log(string name = null)  
14:      {  
15:        Console.WriteLine(name);  
16:      }  
17:    }  
18:    [Serializable]  
19:    public class MyAspec : OnMethodBoundaryAspect  
20:    {  
21:      public override void OnEntry(MethodExecutionArgs args)  
22:      {  
23:        Console.WriteLine("Entering - '{0}'", args.Method);  
24:      }  
25:      public override void OnExit(MethodExecutionArgs args)  
26:      {  
27:        Console.WriteLine("Exiting - '{0}' - '{1}'.", args.Method, args.ReturnValue);  
28:      }  
29:    }  
30:  }  

As you can see we created simple Console application which contains one Aspect class 'MyAspec'. And we marked Log method in Program class with it. Pretty simple, does it?
And the main question, what does my code look like?
Let's look it from dotPeek point of view:


We see two created classes and two resources. The method that we marked with our aspect now looks like this:



You can see our initial method body at line 37, the rest of the code is PostSharp generated code. It contains invocations of OnEntry, OSuccess, OnExit, OnException aspect methods at lines: 32, 39, 45, 63. But there is no MyAspec class, only strange lines with <>z__a_1 class. Let's a look at it.



It has two static fields _1 type of MethodBase and a0 type of MyAspec.
So, how does it all interact?
At start i was confused a little, if you see at our Log method you may be wondering at such lines:

1:  <>z__a_1.a0.OnEntry(args);  

We call method on static field, but where is the initialization? Why doesn't it throw NullReferenceException? I didn't find an answer in dotPeek and looked at it in ILDasm. And it showed me much more.
At first, i found static constructor in my Program class, which was does not present in dotPeek:


It calls Initialize() method of <>z__a_1 which is simple stub, but <>z__a_1 also have static constructor which was not present in dotPeek also. It's how it look like:



It's what i was searching for. It contains initialization the fields of types MethodBase and MyAspec. In order to do it it use another class(which also was not present in dotPeek) <>z__a_2 through static constructor:


So, what PostSharp did for us:
  1. Created static constructor for Program class in which static constructor of <>z__a_1 was called.
  2. The <>z__a_1 in turn initialized two fields: MethodBase with method it applied to and MyAspec - instance was serialized from resource through <>z__a_2
  3. Our body of the Log method was replaced with generated code which is now pretty straightforward.
PS. I used VS 2013, .NET 4.5, PostSharp 4.0.42.






Комментариев нет:

Отправить комментарий