程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Emit學習-實戰篇-實現一個簡單的AOP框架(二)

Emit學習-實戰篇-實現一個簡單的AOP框架(二)

編輯:關於.NET

已經9點了,就不廢話了,直接開講,今天就簡單的介紹下框架中用到的一些接口和屬性。昨天把我們關注的切面分成了三類,現在給出這3個接口的定義:

接口定義

/// <summary>
/// 在調用方法體前執行的處理接口
/// </summary>
public interface IPreProcess
{   
    bool PreProcess(MethodContext methodContext);
}
/// <summary>
/// 在調用方法體後執行的處理接口
/// </summary>
public interface IPostProcess
{
    void PostProcess(MethodContext methodContext);
}
/// <summary>
/// 處理方法調用所產生的異常的接口
/// </summary>
public interface IExceptionHandler
{
    void ProcessException(MethodContext methodContext, Exception exception);
}

l  繼承IPreProcess接口可以實現對方法執行前的處理,該方法傳入一個MethodContext對象,裡面包含了方法執行時的一些上下文信息,然後返回一個bool值,指示是否繼續執行下面的方法;

l  繼承IPostProcess接口可以實現方法執行後的處理,同樣傳入一個MethodContext對象,與之前不同的是,這次的MethodContext對象中還設置了真正的方法體執行後所得到的結果,用於進行一些後續的處理;

l  繼承IExceptionHandler接口可以實現在方法發生異常時的異常處理,該方法中比上面兩個方法多了一個Exception參數,該參數表示截獲到的異常信息。

對於任意一個接口,每個方法都可以有不止一個的處理程序,框架將按照在配置文件中定義的順序依次調用執行。下面給出一個進行方法植入後的偽代碼示例:

偽代碼

public virtual void Test1(string text1)
{
    MethodContext context;
    try
    {
        //調用預處理程序
        if (_addPreProcessLog.PreProcess(context))
        {
            //調用真正的方法
            base.Test1(text1);
            //調用事後處理程序
            _addPostProcessLog.PostProcess(context);
        }
    }
    catch (Exception exception)
    {
        //調用異常處理程序
        _simplyExceptionHandler.ProcessException(context, exception);
    }
}

接下來介紹一下MethodContext類,這個類裡面定義了方法執行時的一些上下文信息,現在有方法的信息、方法調用時傳入的參數、方法的返回值,本來還有方法的調用者,後來感覺沒什麼用,又去掉了,我暫時只能想到這些信息,大家如果有好的意見,希望能在文後留言,感激的話就不說了,共同進步嘛,下面給出類的定義:

MethodContext
/// <summary>
/// 方法執行時的上下文
/// </summary>
public class MethodContext : MarshalByRefObject
{
    #region Properties

    private MethodInfo _methodInfo;
    /// <summary>
    /// 方法的信息
    /// </summary>
    public MethodInfo MethodInfo
    {
        get { return _methodInfo; }
        set { _methodInfo = value; }
    }

    private object[] _arguments;
    /// <summary>
    /// 方法調用時傳入的參數
    /// </summary>
    public object[] Arguments
    {
        get { return _arguments; }
        set { _arguments = value; }
    }

    private object _result;
    /// <summary>
    /// 方法的返回值,如果有
    /// </summary>
    public object Result
    {
        get { return _result; }
        set { _result = value; }
    }

    #endregion

    #region Ctor

    public MethodContext()
    {
    }

    public MethodContext(MethodInfo methodInfo, object[] paras)
    {
        _methodInfo = methodInfo;
        _arguments = paras;
    }

    #endregion
}

今天最後要講的就是昨天在給出的示例中所使用的屬性(感覺叫特性比較不容易搞錯),先給出代碼,再進行講解:

AspectAttribute
[Flags()]
public enum AspectTypes
{
    PreProcess = 1,
    ExceptionHandler = 2,
    PostProcess = 4
}
/// <summary>
/// 描述切面信息的屬性
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class AspectAttribute : Attribute
{
    private AspectTypes _aspectType;

    public AspectTypes AspectType
    {
        get { return _aspectType; }
    }

    public AspectAttribute(AspectTypes aspectType)
    {
        _aspectType = aspectType;
    }
}

首先是一個枚舉類,用來表示方法要使用的切面類型,使用了Flags屬性標識,方便之後進行位操作;然後是繼承自Attribute的屬性類,[AttributeUsage(AttributeTargets.Method)]屬性表示這個屬性只能用在方法上,這正是我們需要的效果,關於屬性的定義和使用大家應該並不陌生吧?我就不多說了,接下來在客戶端就可以用如下的方式進行使用:

[Aspect(AspectTypes.PreProcess | AspectTypes.ExceptionHandler)]

public virtual void Test1(string num)

這就表示這個Test1方法需要進行預處理和異常處理,而具體的處理信息的定義則放在配置文件中,這部分將在明天講到。最後在反射中可以用如下的方式判斷某個方法是否需要進行處理if ((aspectType & AspectTypes.PostProcess) == AspectTypes.PostProcess)(感覺這麼寫很繁瑣,由於是第一次對枚舉進行位運算,也不知道有沒有更簡便的方法,希望知道的能給與指點)。好啦,今天就到此為止!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved