天天看點

C# Aop簡單掃盲及ORM實體類屬性攔截示例

先說下場景,c#中為什麼要使用aop,而我又是在哪裡使用aop?

本人隻是想攔截實體類的set的方法,然後在set之前,調用一下其它方法,把值賦給另一個對象。

而我做的都是在實體類的基類裡處理:

比如:

如果說,我這樣實作:在ormbase中可以提供方法,讓所有的子類的屬性都這樣操作:

C# Aop簡單掃盲及ORM實體類屬性攔截示例

public class users:ormbase

{

public int _id;

public int id 

get;

set

  base.setxx(value);

 }

}

C# Aop簡單掃盲及ORM實體類屬性攔截示例

不過每個實體都這樣寫,雖然是啥沒問題,不過能簡化的還是簡化。

在能追求簡潔的世界裡,當然更喜歡簡潔的寫法如:

public int id {get;set;}

是以,直接在基類裡直接攔截子類set方法,在裡面直接調用setxx就搞定了,如何實作呢?又花了一天的時間查資料研究學習并實作。

為此,要攔截,就得折騰aop:

傳統的aop使用realproxy,使用非常簡單,但是被忽悠的非常複雜,下面:

1:在要攔截的類頭上加個屬性辨別,同時繼承自contextboundobject:

[aopattribute]

public class ormbase:contextboundobject

ok,在基類裡加一個,這樣所有子類也算被附加了,加上一個辨別,就可以被攔截了,那這個aopattribute屬性是啥?看下面

2:aopattribute繼承代理屬性辨別類,用來挂在要攔截的類的頭上:

C# Aop簡單掃盲及ORM實體類屬性攔截示例

    class aopattribute : proxyattribute

    {

        public override marshalbyrefobject createinstance(type servertype)

        {

            aopproxy realproxy = new aopproxy(servertype);

            return realproxy.gettransparentproxy() as marshalbyrefobject;

        }

    }

C# Aop簡單掃盲及ORM實體類屬性攔截示例

看,裡面就兩行,非常簡單,中間調用了繼承realproxy的aopproxy類,aopproxy是什麼,怎麼出來的?看下面

3:aopproxy類,就是攔截的消息處理,先上個簡單版,免的大夥看不懂:

C# Aop簡單掃盲及ORM實體類屬性攔截示例

 class aopproxy : realproxy

        public aopproxy(type servertype)

            : base(servertype)

        public override imessage invoke(imessage msg)

            //消息攔截之後,就會執行這裡的方法。

C# Aop簡單掃盲及ORM實體類屬性攔截示例

ok,簡單吧,就這麼兩個類,就可以實作攔截了,不過重點就是這裡攔截之後的代碼,稍為複雜點,一般照抄就行了,攔截的代碼如下:

C# Aop簡單掃盲及ORM實體類屬性攔截示例

 if (msg is iconstructioncallmessage) // 如果是構造函數,按原來的方式傳回即可。

            {

                iconstructioncallmessage constructcallmsg = msg as iconstructioncallmessage;

                iconstructionreturnmessage constructionreturnmessage = this.initializeserverobject((iconstructioncallmessage)msg);

                realproxy.setstubdata(this, constructionreturnmessage.returnvalue);

                return constructionreturnmessage;

            }

            else if (msg is imethodcallmessage) //如果是方法調用(屬性也是方法調用的一種)

                imethodcallmessage callmsg = msg as imethodcallmessage;

                object[] args = callmsg.args;

                imessage message;

                try

                {

                    if (callmsg.methodname.startswith("set_") && args.length == 1)

                    {

                        //這裡檢測到是set方法,然後應怎麼調用對象的其它方法呢?

                    }

                    object o = callmsg.methodbase.invoke(getunwrappedserver(), args);

                    message = new returnmessage(o, args, args.length, callmsg.logicalcallcontext, callmsg);

                }

                catch (exception e)

                    message = new returnmessage(e, callmsg);

                return message;

            return msg;

C# Aop簡單掃盲及ORM實體類屬性攔截示例

為了調用原始對象的其它方法,我花了近一天的時間查資料,可惜網絡上并沒有相應的資訊,多數的人應用,都是引向一個其它方法(一個不需要調用原始對象的方法)

目前網絡上aop資訊太少,c#的更少,關于如何擷取原始對象,然後調用原始對象的,找不到一篇相關文章,我特糾結。 

于是,我按傳統方式,想盡辦法的想擷取到原始對象,再調用,經過九九八十一招,還是失敗了。

(一開始是想:通過反射從類型再建立一個實體這種不靠譜的嘗試: 造成死循環,每次new攔截,在攔截裡又new)

中間省一大堆......痛苦的經曆和嘗試.......

隻要用心想,方法總有的,最終還是被我發現了:

1:擷取要調用的方法:

在構造函數中,根據傳進來的servertype,擷取到setxx的方法methodinfo:

method = servertype.getmethod("setxx", bindingflags.nonpublic | bindingflags.instance);

2:在攔截方法中調用:

C# Aop簡單掃盲及ORM實體類屬性攔截示例

 if (callmsg.methodname.startswith("set_") && args.length == 1)

   method.invoke(getunwrappedserver(), new object[] { callmsg.methodname.substring(4), args[0] });//對屬性進行調用

  }

C# Aop簡單掃盲及ORM實體類屬性攔截示例

過程很複雜,嘗試過n百種方式,結果很簡單,分享很重要!

為此,解決了orm對子類的屬性攔截,并實作了在屬性指派時調用執行個體其它方法。