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


先說下場景,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對子類的屬性攔截,並實現了在屬性賦值時調用實例其它方法。


免責聲明!

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



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