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

來源:互聯網
上載者:User
先說下情境,C#中為什麼要使用Aop,而我又是在哪裡使用Aop?
本人只是想攔截實體類的Set的方法,然後在Set之前,調用一下其它方法,把值賦給另一個對象。

 

而我做的都是在實體類的基類裡處理:比如: public class OrmBase

 

讓所有繼承這個基類的實體類都具有Orm操作功能,再加上一個小小特殊的要求處理,屬性Set時,需要對另一對象賦值。

 

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

 

public class Users:OrmBase{public int _ID;public int ID {get;set{  base.SetXX(value); }} 

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

 

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

public int ID {get;set;}

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

 

為此,要攔截,就得折騰Aop:傳統的Aop使用RealProxy,使用非常簡單,但是被忽悠的非常複雜,下面:

 

1:在要攔截的類頭上加個屬性標識,同時繼承自ContextBoundObject:

 

[AopAttribute]public class OrmBase:ContextBoundObject 

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

 

2:AopAttribute繼承代理屬性標識類,用來掛在要攔截的類的頭上:

 

    class AopAttribute : ProxyAttribute    {        public override MarshalByRefObject CreateInstance(Type serverType)        {            AopProxy realProxy = new AopProxy(serverType);            return realProxy.GetTransparentProxy() as MarshalByRefObject;        }    } 

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

 

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

 

 class AopProxy : RealProxy    {        public AopProxy(Type serverType)            : base(serverType)        {        }        public override IMessage Invoke(IMessage msg)        {            //訊息攔截之後,就會執行這裡的方法。        }    }

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

 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;

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

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

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

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

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

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

1:擷取要調用的方法:

在建構函式中,根據傳進來的serverType,擷取到SetXX的方法MethodInfo:

method = serverType.GetMethod("SetXX", BindingFlags.NonPublic | BindingFlags.Instance);

2:在攔截方法中調用:

 if (callMsg.MethodName.StartsWith("set_") && args.Length == 1)

{

   method.Invoke(GetUnwrappedServer(), new object[] { callMsg.MethodName.Substring(4), args[0] });//對屬性進行調用

  }

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

為此,解決了ORM對子類的屬性攔截,並實現了在屬性賦值時調用執行個體其它方法。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.