C# 使用Emit實現動態AOP框架 (一)


     目  錄

C# 使用Emit實現動態AOP框架 (一)

C# 使用Emit實現動態AOP框架 (二)

C# 使用Emit實現動態AOP框架 (三)

C# 使用Emit實現動態AOP框架 進階篇之異常處理

C# 使用Emit實現動態AOP框架 進階篇之優化

  最近需要有一個完全自主的基於C#語言的Aop框架,查了一下資料實現方式主要分為:靜態織入和動態代理,靜態織入以Postshop為代表,而動態代理又分為:

1、普通反射

2、Emit反射

3、微軟提供的.Net Remoting和RealProxy

(微軟官方例子https://msdn.microsoft.com/zh-cn/library/dn574804.aspx

      總體來說靜態織入速度最快,普通反射最慢,而.Net Remoting和RealProx實現起來又相對較復雜。而Emit速度居中,同時其一次生成后,將結果序列化,速度也並不慢,同時和原有類並沒有緊密耦合,通過外部配置文件可以方便的控制要進行代理的類型、方法和屬性,其缺點是被代理的方法、屬性必須為virtual類型。

一、被代理類和代理類

       被代理類,是我們正常使用的類,里邊是原有的業務邏輯,只要在被代理方法上申明上相應的切面特性就行了,使用起來比較簡單;如下

 1   public class AopTest
 2   {
 3         
 4         public AopTest()
 5         {
 6             Name = "小明"; Age = 10;
 7         }
 8 
 9         public AopTest(string name, int age)
10         {
11             Name = name; Age = age;
12         }
13 
14         [Log]
15         public virtual string Name { get; set; }
16 
17         [Log]
18         public virtual int Age { get; set; }
19 
20         [Log]
21         public virtual int NYearLater(int a)
22         {
23             int larter = Age + a;
24 
25             return larter;
26         }
27     }

 

     代理類是Aop框架自動生成的類,使用反編譯工具我們可以看到,它比被代理類多了切面上下文聲明(AspectContent)和相應的切面特性對象聲明,在被代理類的方法執行前后,相應切面特性調用OnEntry、OnExit執行相關操作,如日志、參數驗證、權限驗證等等Aop功能,其中AspectContext是OnEntry、OnExit調用參數,如下:

public class AopTest_Proxy : AopTest
{
    public override string Name
    {
        get
        {
            object[] args = new object[0];
            AspectContext aspectContext = new AspectContext(this, "get_Name", args);
            LogAttribute logAttribute = new LogAttribute();
            logAttribute.OnEntry(aspectContext);
            string name = base.Name;
            aspectContext.Result = name;
            logAttribute.OnExit(aspectContext);
            return name;
        }
        set
        {
            AspectContext context = new AspectContext(this, "set_Name", new object[]
            {
                value
            });
            LogAttribute logAttribute = new LogAttribute();
            logAttribute.OnEntry(context);
            base.Name = value;
            logAttribute.OnExit(context);
        }
    }

    public override int Age
    {
        get
        {
            object[] args = new object[0];
            AspectContext aspectContext = new AspectContext(this, "get_Age", args);
            LogAttribute logAttribute = new LogAttribute();
            logAttribute.OnEntry(aspectContext);
            int age = base.Age;
            aspectContext.Result = age;
            logAttribute.OnExit(aspectContext);
            return age;
        }
        set
        {
            AspectContext context = new AspectContext(this, "set_Age", new object[]
            {
                value
            });
            LogAttribute logAttribute = new LogAttribute();
            logAttribute.OnEntry(context);
            base.Age = value;
            logAttribute.OnExit(context);
        }
    }

    public AopTest_Proxy(string name, int age) : base(name, age)
    {
    }

    public override int NYearLater(int num)
    {
        AspectContext aspectContext = new AspectContext(this, "NYearLater", new object[]
        {
            num
        });
        LogAttribute logAttribute = new LogAttribute();
        logAttribute.OnEntry(aspectContext);
        int num2 = base.NYearLater(num);
        aspectContext.Result = num2;
        logAttribute.OnExit(aspectContext);
        return num2;
    }
}

 

二、測試方法

public static void Test()
{
  try
  {
     AopTest WithPara = DynamicProxy.Create<AopTest>("lxl", 10); ;
 
     WithPara.NYearLater(10);
     Console.WriteLine("done...");
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
   }
 }

 

測試方法中:AopTest WithPara = DynamicProxy.Create<AopTest>("lxl", 10); ,生成一個代理對象,其他就正常使用就可以了。

調用測試方法執行結果如下:

Log OnEntry:set_Name(lxl)
Log OnExit: set_Name

Log OnEntry:set_Age(10)
Log OnExit: set_Age

Log OnEntry:NYearLater(10)
Log OnEntry:get_Age()
Log OnExit: get_Age Result: 10

Log OnExit: NYearLater Result: 20

done...

 

   通過結果可以看到 屬性Name、Age的Set方法,NYearLater方法,以及Age屬性的Get方法都實現了日志記錄。下邊將分幾篇來詳細介紹DynamicProxy類的實現。歡迎大家多多指正、交流。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM