已經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)(感覺這麼寫很繁瑣,由於是第一次對枚舉進行位運算,也不知道有沒有更簡便的方法,希望知道的能給與指點)。好啦,今天就到此為止!