動態代理的一個最主要的應用場合就是實現AOP - 截獲方法調用,加入自己的預處理、后處理或Around處理。
我在ESBasic.Emit中實現了對這些截獲的支持。
首先,介紹兩個截獲者:
在上面的接口方法中都有一個參數InterceptedMethod,它封裝了被截獲的目標方法的基本信息。
好,如何使用ESBasic.Emit來創建動態代理了?很簡單,你只需要調用
public
static
TInterfaceCreateAopProxy
<
TInterface
>
(
object
origin,
IMethodInterceptor
methodInterceptor,
IAroundInterceptor
aroundInterceptor)
如果不需要某種截獲處理,對應的參數傳入null即可。
舉個例子,我們需要使用動態代理截獲IComputer所有方法調用拋出的異常,并記錄日志。IComputer定義如下:
最后,提醒一下,如果你讓Computer不從IComputer繼承,運行結果也一樣。你應該已經看到 DynamicProxyFactory .CreateAopProxy方法的第一個參數是object類型,而不是泛型T,這說明只要對應的object包含了和目標接口一樣的方法(簽名完全一致)就可以 -- 這就是所謂的“換臉”能力,可以在 這里 看到更詳細的說明。
由于動態代理是使用Emit發射實現,所以效率上來說,和你手寫的代碼是沒有區別的。
下載 ESBasic.Emit.dll。
我在ESBasic.Emit中實現了對這些截獲的支持。
首先,介紹兩個截獲者:
///
<summary>
/// IMethodInterceptor對方法進行截獲并加入預處理和后處理。
/// </summary>
public interface IMethodInterceptor
{
void PreProcess( InterceptedMethod method);
void PostProcess( InterceptedMethod method, object returnVal);
}
IMethodInterceptor 很容易理解,用于為截獲插入預處理、后處理。這個非常容易理解。
/// IMethodInterceptor對方法進行截獲并加入預處理和后處理。
/// </summary>
public interface IMethodInterceptor
{
void PreProcess( InterceptedMethod method);
void PostProcess( InterceptedMethod method, object returnVal);
}
///
<summary>
/// IAroundInterceptor對方法進行Around截獲處理。注意,必須要觸發目標方法的調用。
/// </summary>
public interface IAroundInterceptor
{
object AroundCall( InterceptedMethod method);
}
Around處理由IAroundInterceptor完成。什么是Around處理了?比如,我們想捕獲目標方法的異常,需要使用TryCatch將目標方法Around起來,這就是Around處理的一個例子。
/// IAroundInterceptor對方法進行Around截獲處理。注意,必須要觸發目標方法的調用。
/// </summary>
public interface IAroundInterceptor
{
object AroundCall( InterceptedMethod method);
}
在上面的接口方法中都有一個參數InterceptedMethod,它封裝了被截獲的目標方法的基本信息。
public
sealed
class
InterceptedMethod
{
#region Ctor
public InterceptedMethod(){}
public InterceptedMethod( object _target,MethodInfo_method, object []paras)
{
this .target = _target;
this .method = _method;
this .arguments = paras;
}
#endregion
#region Method
private MethodInfomethod;
/// <summary>
/// Method被截獲的目標方法
/// </summary>
public MethodInfo Method
{
get { return method;}
set {method = value;}
}
#endregion
#region Target
private object target;
/// <summary>
/// Target被截獲的方法需要在哪個對象上調用。
/// </summary>
public object Target
{
get { return target;}
set {target = value;}
}
#endregion
#region Arguments
private object []arguments;
/// <summary>
/// Arguments調用被截獲的方法的參數
/// </summary>
public object []Arguments
{
get { return arguments;}
set {arguments = value;}
}
#endregion
#region Invoke
/// <summary>
/// Invoke執行目標方法
/// </summary>
public object Invoke()
{
return this .method.Invoke( this .target, this .arguments);
}
#endregion
}
{
#region Ctor
public InterceptedMethod(){}
public InterceptedMethod( object _target,MethodInfo_method, object []paras)
{
this .target = _target;
this .method = _method;
this .arguments = paras;
}
#endregion
#region Method
private MethodInfomethod;
/// <summary>
/// Method被截獲的目標方法
/// </summary>
public MethodInfo Method
{
get { return method;}
set {method = value;}
}
#endregion
#region Target
private object target;
/// <summary>
/// Target被截獲的方法需要在哪個對象上調用。
/// </summary>
public object Target
{
get { return target;}
set {target = value;}
}
#endregion
#region Arguments
private object []arguments;
/// <summary>
/// Arguments調用被截獲的方法的參數
/// </summary>
public object []Arguments
{
get { return arguments;}
set {arguments = value;}
}
#endregion
#region Invoke
/// <summary>
/// Invoke執行目標方法
/// </summary>
public object Invoke()
{
return this .method.Invoke( this .target, this .arguments);
}
#endregion
}
好,如何使用ESBasic.Emit來創建動態代理了?很簡單,你只需要調用

舉個例子,我們需要使用動態代理截獲IComputer所有方法調用拋出的異常,并記錄日志。IComputer定義如下:
public
interface
IComputer
{
int Add( int a, int b);
}
public class Computer: IComputer
{
public int Add( int a, int b)
{
throw new Exception( " TestException " );
return a + b;
}
}
我可以使用Around截獲者來截獲異常,所以我實現一個自己的IAroundInterceptor:
{
int Add( int a, int b);
}
public class Computer: IComputer
{
public int Add( int a, int b)
{
throw new Exception( " TestException " );
return a + b;
}
}
public
class
ExceprionAroundInterceptor
:
IAroundInterceptor
{
#region IAroundInterceptor成員
public object AroundCall( InterceptedMethod method)
{
try
{
return method.Invoke();
}
catch (Exceptionee)
{
ee = ee;
//
..logException
throw ;
}
}
#endregion
}
現在,我們可以這樣獲得針對IComputer的動態代理的引用:
{
#region IAroundInterceptor成員
public object AroundCall( InterceptedMethod method)
{
try
{
return method.Invoke();
}
catch (Exceptionee)
{
ee = ee;
//


throw ;
}
}
#endregion
}
IComputer
proxy
=
ESBasic.Emit.Application.
DynamicProxyFactory
.CreateAopProxy
<
IComputer
>
(
new
Computer
(),
null
,
new
ExceprionAroundInterceptor
());
proxy.Add( 1 , 2 );
這樣就ok了,Add方法拋出的異常會被
ExceprionAroundInterceptor
截獲。
proxy.Add( 1 , 2 );
最后,提醒一下,如果你讓Computer不從IComputer繼承,運行結果也一樣。你應該已經看到 DynamicProxyFactory .CreateAopProxy方法的第一個參數是object類型,而不是泛型T,這說明只要對應的object包含了和目標接口一樣的方法(簽名完全一致)就可以 -- 這就是所謂的“換臉”能力,可以在 這里 看到更詳細的說明。
由于動態代理是使用Emit發射實現,所以效率上來說,和你手寫的代碼是沒有區別的。
下載 ESBasic.Emit.dll。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
