zl程序教程

您现在的位置是:首页 >  后端

当前栏目

关于.NET动态代理的介绍和应用简介

Net代理应用 介绍 简介 关于 动态
2023-06-13 09:13:42 时间
  引言

  假如现在我们有这样在这个示例中我将使用尽可能简单的逻辑实现所有功能需求,这将更突出我们所要解决的核心问题。例子是一个简单计算器类:

publicclassCalculator
{
 publicintAdd(intx,inty){returnx+y;}
}

  这个类再简单不过了,不过若你将它想象为一个可能更复杂的业务处理类的时候,你将面临除了核心功能实现之外的更多处理细节,比如说:权限控制、审计日志、性能监测、缓冲处理、事务环境等等。为简单起见,我们首先为该类增加记录日志的功能,该功能要求将对每个方法的调用和处理结果输出到Console中,如下:

publicclassCalculator
{
 publicintAdd(intx,inty)
 {
  Console.Write("Add({0},{1})",x,y);
  intresult=x+y;
  Console.WriteLine("={0}",result);
  returnresult;
 }
}

  再简单不过了,对吧?现在我们需要为该方法实现性能监测,如下:

publicclassCalculator
{
 publicintAdd(intx,inty)
 {
  Console.Write("Add({0},{1})",x,y);
  DateTimeTimeBegin=System.DateTime.Now;
  intresult=x+y;
  TimeSpanTimeInter=System.DateTime.Now-TimeBegin;
  Console.Write("[{0}]",TimeInter);
  Console.WriteLine("={0}",result);
  returnresult;
 }
}

  此时你已经感觉到,虽然我们实现了所需的功能,但是在一个方法中堆叠了处理各类事宜的不同代码。虽然在这个简单例子中不会感觉有什么不爽,但是请你想象一下如果我们将为该类添加第二个方法时会发生什么事情:

publicclassCalculator
{
 publicintAdd(intx,inty)
 {
  Console.Write("Add({0},{1})",x,y);
  DateTimeTimeBegin=System.DateTime.Now;
  intresult=x+y;
  TimeSpanTimeInter=System.DateTime.Now-TimeBegin;
  Console.Write("[{0}]",TimeInter);
  Console.WriteLine("={0}",result);
  returnresult;
 }
 publicintSubtract(intx,inty)
 {
  Console.Write("Subtract({0},{1})",x,y);
  DateTimeTimeBegin=System.DateTime.Now;
  intresult=x-y;
  TimeSpanTimeInter=System.DateTime.Now-TimeBegin;
  Console.Write("[{0}]",TimeInter);
  Console.WriteLine("={0}",result);
  returnresult;
 }
}

  在两个方法中已经明显出现重复代码了,这可不是一个好的解决办法——想想一下如果我们的计算器有10个方法呢?如果我们还有类似于计算器类的另外数十个类呢?如果我们还有更多的方法级功能要实现呢(权限控制、事务管理……)?在企业级应用开发中,这可是一个经常会遇的问题。为清楚起见,我们将问题分解成两部分,首要的问题是代码职责混淆,其次则是同样的代码逻辑反复多次——这些问题都将导致开发管理、代码编写与维护的各种困难。

  方案一:自己手动编写代理解决

  1、首先我们定义接口ICalculator:

usingSystem;
namespaceProxy
{
 publicinterfaceICalculator
 {
  intAdd(intx,inty);
  intSubtract(intx,inty);
 }
}
  2、具体实现一个接口:

usingSystem;
namespaceProxy
{
 publicclassCalculator:ICalculator
 {
  publicvirtualintAdd(intx,inty)
  {
   intresult=x+y;
   returnresult;
  }
  publicvirtualintSubtract(intx,inty)
  {
   intresult=x-y;
   returnresult;
  }
 }
}  3、编写增加日志和性能检测功能的代理类

  增加记录日志的功能,即功能要求将对每个方法的调用和处理结果输出到Console;增加性能监测。

  有两种实现方式,注释了其中的一种

usingSystem;
namespaceProxy
{
 /////<summary>
 /////CalProxy的摘要说明。
 /////</summary>
 //publicclassCalProxy:ICalculator
 //{
 //privateCalculator_Calculator;
 //publicCalProxy()
 //{
 //this._Calculator=newCalculator();
 //}
 //privateDateTimeTimeBegin=System.DateTime.Now;
 //privatevoidPreDoSomething(intx,inty)
 //{
 //TimeBegin=System.DateTime.Now;
 //Console.Write("Number({0},{1})\n",x,y);
 //}
 ////实现add
 //publicvirtualintAdd(intx,inty)
 //{
 //this.PreDoSomething(x,y);
 //intresult=this._Calculator.Add(x,y);
 //this.PostDoSomething(result);
 //returnresult;
 //}
 ////实现sub
 //publicvirtualintSubtract(intx,inty)
 //{
 //this.PreDoSomething(x,y);
 //intresult=this._Calculator.Subtract(x,y);
 //this.PostDoSomething(result);
 //returnresult;
 //}
 //privatevoidPostDoSomething(intresult)
 //{
 //TimeSpanTimeInter=System.DateTime.Now-TimeBegin;
 //Console.Write("运行时间[{0}]\n",TimeInter);
 //Console.WriteLine("运行结果={0}\n",result);
 //}
 //}
 ///<summary>
 ///CalProxy的摘要说明。
 ///</summary>

 publicclassCalProxy:Calculator
 {
  publicCalProxy()
  {}
  privateDateTimeTimeBegin=System.DateTime.Now;
  privatevoidPreDoSomething(intx,inty)
  {
   TimeBegin=System.DateTime.Now;
   Console.Write("Number({0},{1})\n",x,y);
  }
  //实现add
  publicoverrideintAdd(intx,inty)
  {
   this.PreDoSomething(x,y);
   intresult=base.Add(x,y);
   this.PostDoSomething(result);
   returnresult;
  }
  //实现sub
  publicoverrideintSubtract(intx,inty)
  {
   this.PreDoSomething(x,y);
   intresult=base.Subtract(x,y);
   this.PostDoSomething(result);
   returnresult;
  }
  privatevoidPostDoSomething(intresult)
  {
   TimeSpanTimeInter=System.DateTime.Now-TimeBegin;
   Console.Write("运行时间[{0}]\n",TimeInter);
   Console.WriteLine("运行结果={0}\n",result);
  }
 }
}
  4、外界的调用方式

ICalculatorICal=newProxy.CalProxy();

ICal.Add(5,3);

ICal.Subtract(7,2);
  运行程序的结果:

Number(5,3)

  运行时间[00:00:02.0156250]

  运行结果=8

  Number(7,2)

  运行时间[00:00:03]

  运行结果=5

  方案二:通过使用Castle.DynamicProxy,实现Iinterceptor解决

  步骤1,2与解决问题

  3、实现StandardInterceptor,增加日志和性能监测功能

  StandardInterceptor是接口Iinterceptor的一个实现类,我们实现StandardInterceptor

usingSystem;
usingSystem.Collections;
usingCastle.DynamicProxy;

namespaceProxy
{
 ///<summary>
 ///ProxyInterceptor拦截器实现了日志和性能监测
 ///</summary>

 publicclassProxyInterceptor:StandardInterceptor
 {
  privateSystem.DateTimeTimeBegin=System.DateTime.Now;
  publicProxyInterceptor()
  {}
  protectedoverridevoidPostProceed(IInvocationinvocation,refobjectreturnValue,paramsobject[]arguments)
  {
   TimeSpanTimeInter=System.DateTime.Now-TimeBegin;
   Console.Write("运行时间[{0}]\n",TimeInter);
   Console.WriteLine("运行结果={0}\n",returnValue);
   base.PostProceed(invocation,refreturnValue,arguments);
  }
  protectedoverridevoidPreProceed(IInvocationinvocation,paramsobject[]args)
  {
   Console.Write("Number({0},{1})\n",args[0],args[1]);
   TimeBegin=System.DateTime.Now;
   base.PreProceed(invocation,args);
  }
  publicoverrideobjectIntercept(IInvocationinvocation,paramsobject[]args)
  {
   PreProceed(invocation,args);
   objectretValue=invocation.Proceed(args);
   PostProceed(invocation,refretValue,args);
   returnretValue;
  }
 }
}
  4、使用Castle.DynamicProxy调用

ProxyGeneratorgenerator=newProxyGenerator();
objectproxy=generator.CreateClassProxy(typeof(Calculator),newProxyInterceptor());
ICalculatorICalCastle=proxyasICalculator;
ICalCastle.Add(5,3);
ICalCastle.Subtract(7,2);


  实现过程:首先通过代码生成完成一个代理类,该代理类继承自要织入的类。然后在代理类中覆盖要拦截的方法,并在覆盖的方法中封装Invocation对象,并传给用户传入的Intercepter对象的Intercept方法。在Intercept方法依次调用Intercepter的PreProcess,通过Invocation传入的Delegate指向的回调函数,Intercepter的PostProcess方法,从而达到拦截的目的。

  意义

  在aop领域可以将日志,事务,缓存等附加功能用此实现。