關(guān)于.NET動(dòng)態(tài)代理的介紹和應(yīng)用簡(jiǎn)介
假如現(xiàn)在我們有這樣在這個(gè)示例中我將使用盡可能簡(jiǎn)單的邏輯實(shí)現(xiàn)所有功能需求,這將更突出我們所要解決的核心問(wèn)題。例子是一個(gè)簡(jiǎn)單計(jì)算器類(lèi):
{
public int Add(int x, int y) { return x + y; }
}
這個(gè)類(lèi)再簡(jiǎn)單不過(guò)了,不過(guò)若你將它想象為一個(gè)可能更復(fù)雜的業(yè)務(wù)處理類(lèi)的時(shí)候,你將面臨除了核心功能實(shí)現(xiàn)之外的更多處理細(xì)節(jié),比如說(shuō):權(quán)限控制、審計(jì)日志、性能監(jiān)測(cè)、緩沖處理、事務(wù)環(huán)境等等。為簡(jiǎn)單起見(jiàn),我們首先為該類(lèi)增加記錄日志的功能,該功能要求將對(duì)每個(gè)方法的調(diào)用和處理結(jié)果輸出到Console中,如下:
{
public int Add(int x, int y)
{
Console.Write("Add({0},{1})", x, y);
int result = x + y;
Console.WriteLine(" = {0}", result);
return result;
}
}
再簡(jiǎn)單不過(guò)了,對(duì)吧?現(xiàn)在我們需要為該方法實(shí)現(xiàn)性能監(jiān)測(cè),如下:
{
public int Add(int x, int y)
{
Console.Write("Add({0},{1})", x, y);
DateTime TimeBegin = System.DateTime.Now;
int result = x + y;
TimeSpan TimeInter =System.DateTime.Now-TimeBegin;
Console.Write(" [{0}] ", TimeInter);
Console.WriteLine(" = {0}", result);
return result;
}
}
此時(shí)你已經(jīng)感覺(jué)到,雖然我們實(shí)現(xiàn)了所需的功能,但是在一個(gè)方法中堆疊了處理各類(lèi)事宜的不同代碼。雖然在這個(gè)簡(jiǎn)單例子中不會(huì)感覺(jué)有什么不爽,但是請(qǐng)你想象一下如果我們將為該類(lèi)添加第二個(gè)方法時(shí)會(huì)發(fā)生什么事情:
{
public int Add(int x, int y)
{
Console.Write("Add({0},{1})", x, y);
DateTime TimeBegin = System.DateTime.Now;
int result = x + y;
TimeSpan TimeInter =System.DateTime.Now-TimeBegin;
Console.Write(" [{0}] ", TimeInter);
Console.WriteLine(" = {0}", result);
return result;
}
public int Subtract(int x, int y)
{
Console.Write("Subtract({0},{1})", x, y);
DateTime TimeBegin = System.DateTime.Now;
int result = x - y;
TimeSpan TimeInter =System.DateTime.Now-TimeBegin;
Console.Write(" [{0}] ", TimeInter);
Console.WriteLine(" = {0}", result);
return result;
}
}
在兩個(gè)方法中已經(jīng)明顯出現(xiàn)重復(fù)代碼了,這可不是一個(gè)好的解決辦法——想想一下如果我們的計(jì)算器有10個(gè)方法呢?如果我們還有類(lèi)似于計(jì)算器類(lèi)的另外數(shù)十個(gè)類(lèi)呢?如果我們還有更多的方法級(jí)功能要實(shí)現(xiàn)呢(權(quán)限控制、事務(wù)管理……)?在企業(yè)級(jí)應(yīng)用開(kāi)發(fā)中,這可是一個(gè)經(jīng)常會(huì)遇的問(wèn)題。為清楚起見(jiàn),我們將問(wèn)題分解成兩部分,首要的問(wèn)題是代碼職責(zé)混淆,其次則是同樣的代碼邏輯反復(fù)多次——這些問(wèn)題都將導(dǎo)致開(kāi)發(fā)管理、代碼編寫(xiě)與維護(hù)的各種困難。
方案一:自己手動(dòng)編寫(xiě)代理解決
1、首先 我們定義接口ICalculator:
namespace Proxy
{
public interface ICalculator
{
int Add(int x, int y);
int Subtract(int x, int y);
}
}
2、具體實(shí)現(xiàn)一個(gè)接口:
namespace Proxy
{
public class Calculator:ICalculator
{
public virtual int Add(int x, int y)
{
int result = x + y;
return result;
}
public virtual int Subtract(int x, int y)
{
int result = x - y;
return result;
}
}
}
增加記錄日志的功能,即功能要求將對(duì)每個(gè)方法的調(diào)用和處理結(jié)果輸出到Console;增加性能監(jiān)測(cè)。
有兩種實(shí)現(xiàn)方式 ,注釋了其中的一種
namespace Proxy
{
// /// <summary>
// /// CalProxy 的摘要說(shuō)明。
// /// </summary>
// public class CalProxy:ICalculator
// {
// private Calculator _Calculator;
// public CalProxy()
// {
// this._Calculator=new Calculator();
// }
// private DateTime TimeBegin = System.DateTime.Now;
// private void PreDoSomething(int x, int y)
// {
// TimeBegin = System.DateTime.Now;
// Console.Write("Number({0},{1})\n", x, y);
// }
// //實(shí)現(xiàn)add
// public virtual int Add(int x, int y)
// {
// this.PreDoSomething(x,y);
// int result = this._Calculator.Add(x,y);
// this.PostDoSomething(result);
// return result;
// }
// //實(shí)現(xiàn)sub
// public virtual int Subtract(int x, int y)
// {
// this.PreDoSomething(x,y);
// int result = this._Calculator.Subtract(x,y);
// this.PostDoSomething(result);
// return result;
// }
// private void PostDoSomething(int result)
// {
// TimeSpan TimeInter =System.DateTime.Now-TimeBegin;
// Console.Write(" 運(yùn)行時(shí)間[{0}]\n ", TimeInter);
// Console.WriteLine(" 運(yùn)行結(jié)果= {0}\n", result);
// }
// }
/// <summary>
/// CalProxy 的摘要說(shuō)明。
/// </summary>
public class CalProxy:Calculator
{
public CalProxy()
{}
private DateTime TimeBegin = System.DateTime.Now;
private void PreDoSomething(int x, int y)
{
TimeBegin = System.DateTime.Now;
Console.Write("Number({0},{1})\n", x, y);
}
//實(shí)現(xiàn)add
public override int Add(int x, int y)
{
this.PreDoSomething(x,y);
int result = base.Add(x,y);
this.PostDoSomething(result);
return result;
}
//實(shí)現(xiàn)sub
public override int Subtract(int x, int y)
{
this.PreDoSomething(x,y);
int result = base.Subtract(x,y);
this.PostDoSomething(result);
return result;
}
private void PostDoSomething(int result)
{
TimeSpan TimeInter =System.DateTime.Now-TimeBegin;
Console.Write(" 運(yùn)行時(shí)間[{0}]\n ", TimeInter);
Console.WriteLine(" 運(yùn)行結(jié)果= {0}\n", result);
}
}
}
4、外界的調(diào)用方式
ICal.Add(5,3);
ICal.Subtract(7,2);
運(yùn)行程序的結(jié)果:
Number(5,3)
運(yùn)行時(shí)間[00:00:02.0156250]
運(yùn)行結(jié)果= 8
Number(7,2)
運(yùn)行時(shí)間[00:00:03]
運(yùn)行結(jié)果= 5
方案二:通過(guò)使用Castle.DynamicProxy,實(shí)現(xiàn)Iinterceptor解決
步驟1,2與解決問(wèn)題
3、實(shí)現(xiàn)StandardInterceptor,增加日志和性能監(jiān)測(cè)功能
StandardInterceptor是接口Iinterceptor的一個(gè)實(shí)現(xiàn)類(lèi),我們實(shí)現(xiàn)StandardInterceptor
using System.Collections;
using Castle.DynamicProxy;
namespace Proxy
{
/// <summary>
/// ProxyInterceptor 攔截器 實(shí)現(xiàn)了日志和性能監(jiān)測(cè)
/// </summary>
public class ProxyInterceptor:StandardInterceptor
{
private System.DateTime TimeBegin=System.DateTime.Now;
public ProxyInterceptor()
{}
protected override void PostProceed(IInvocation invocation, ref object returnValue, params object[] arguments)
{
TimeSpan TimeInter =System.DateTime.Now-TimeBegin;
Console.Write(" 運(yùn)行時(shí)間[{0}]\n ", TimeInter);
Console.WriteLine(" 運(yùn)行結(jié)果= {0}\n", returnValue);
base.PostProceed(invocation, ref returnValue, arguments);
}
protected override void PreProceed(IInvocation invocation, params object[] args)
{
Console.Write("Number({0},{1})\n", args[0], args[1]);
TimeBegin=System.DateTime.Now;
base.PreProceed(invocation, args);
}
public override object Intercept(IInvocation invocation, params object[] args)
{
PreProceed(invocation, args);
object retValue = invocation.Proceed( args );
PostProceed(invocation, ref retValue, args);
return retValue;
}
}
}
4、使用Castle.DynamicProxy調(diào)用
object proxy = generator.CreateClassProxy(typeof(Calculator), new ProxyInterceptor());
ICalculator ICalCastle=proxy as ICalculator;
ICalCastle.Add(5,3);
ICalCastle.Subtract(7,2);
實(shí)現(xiàn)過(guò)程:首先通過(guò)代碼生成完成一個(gè)代理類(lèi),該代理類(lèi)繼承自要織入的類(lèi)。然后在代理類(lèi)中覆蓋要攔截的方法,并在覆蓋的方法中封裝Invocation對(duì)象,并傳給用戶(hù)傳入的Intercepter對(duì)象的Intercept方法。在Intercept方法依次調(diào)用Intercepter的PreProcess,通過(guò)Invocation傳入的Delegate指向的回調(diào)函數(shù),Intercepter的PostProcess方法,從而達(dá)到攔截的目的。
意義
在aop領(lǐng)域 可以將日志,事務(wù),緩存等附加功能用此實(shí)現(xiàn)。
相關(guān)文章
用戶(hù)控件(ASCX)向網(wǎng)頁(yè)(ASPX)傳值使用反射實(shí)現(xiàn)
用戶(hù)控件向網(wǎng)頁(yè)傳遞值,網(wǎng)上的方法有很多,本文嘗試一下使用反射來(lái)實(shí)現(xiàn),感興趣的朋友可以參考下哈,希望可以幫助到你2013-03-03教你Asp.net下使用mysql數(shù)據(jù)庫(kù)的步驟
近日,在項(xiàng)目中遇到了麻煩,客戶(hù)非要求使用mysql數(shù)據(jù)庫(kù),對(duì)于我從來(lái)么有使用過(guò)的人來(lái)說(shuō),很是頭疼,最后還是硬著頭皮弄好了。期間也遇到了各種各樣的問(wèn)題,現(xiàn)在把他整理在此,希望對(duì)那些和我一樣從來(lái)沒(méi)有使用過(guò)的人,能快速入手2012-05-05Entity?Framework代碼優(yōu)先Code?First入門(mén)
這篇文章介紹了Entity?Framework的代碼優(yōu)先模式Code?First,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06asp.net 獨(dú)立Discuz頭像編輯模塊分離打包
在Discuz產(chǎn)品系列(包括UCenter、UCHome)中有一個(gè)flash頭像上傳編輯的功能比較好用,和之前自己用js實(shí)現(xiàn)的照片在線編輯插件比較像,于是想將它獨(dú)立出來(lái),一方面可以學(xué)習(xí)研究,另一方面有機(jī)會(huì)可以在項(xiàng)目中使用(這里主要是指Asp.Net程序,php的與之類(lèi)似)。2011-06-06動(dòng)態(tài)指定任意類(lèi)型的ObjectDataSource對(duì)象的查詢(xún)參數(shù)
我在使用ObjectDataSource控件在ASP.NET中實(shí)現(xiàn)Ajax真分頁(yè) 一文中詳細(xì)介紹過(guò)如何使用ObjectDataSource和ListView實(shí)現(xiàn)數(shù)據(jù)綁定和分頁(yè)功能。事實(shí)上,采用ObjectDataSource和ListView相結(jié)合,可以減少我們很多的開(kāi)發(fā)任務(wù)。2009-11-11