博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
动态方法与动态代理(下篇)
阅读量:6293 次
发布时间:2019-06-22

本文共 8409 字,大约阅读时间需要 28 分钟。

动态代理:

  代理模式和装饰模式的区别:

  装饰模式:在不改变接口的前提下,动态扩展对象的功能

      代理模式:在不改变接口的前提下,控制对象的访问

      代理类和被代理对象是has-a关系,一般没有is-a关系,除非代理类直接继承被代理类,重写被代理类的方法

动态代理是指通过动态代码技术在运行时生成具体类的代理,目的是在执行具体类的操作之前或之后运行特定的逻辑

动态代理既可以代理类也可以代理接口,代理类时,被代理的类不能为Sealed,并且其中属性和方法都必须为Virtual,而代理接口时则无约束条件

 •Demo:动态生成接口的代理

 

ExpandedBlockStart.gif
View Code
  1 
 
public
 
interface
 ICalculate
  2 
    {
  3 
        
void
 Add(
int
 a, 
int
 b);
  4 
    }
  5 
  6 
    
public
 
class
 A : ICalculate
  7 
    {
  8 
        
#region
 ICalculate 成员
  9 
 10 
        
public
 
void
 Add(
int
 a, 
int
 b)
 11 
        {
 12 
            Console.WriteLine(a 
+
 b);
 13 
        }
 14 
 15 
        
#endregion
 16 
    }
 17 
 18 
    
public
 
class
 B : ICalculate
 19 
    {
 20 
        ICalculate _inst;
 21 
 22 
        
public
 B(ICalculate o)
 23 
        {
 24 
            _inst 
=
 o;
 25 
        }
 26 
 27 
        
#region
 ICalculate 成员
 28 
 29 
        
public
 
void
 Add(
int
 a, 
int
 b)
 30 
        {
 31 
            Console.WriteLine(
"
Before...
"
);
 32 
            _inst.Add(a, b);
 33 
            Console.WriteLine(
"
After...
"
);
 34 
        }
 35 
 36 
        
#endregion
 37 
    }
 38 
 39 
    
class
 Program
 40 
    {
 41 
        
static
 
void
 Main(
string
[] args)
 42 
        {
 43 
            Type proxyType;
//
代理类型
 44 
 45 
            
#region
 Emit Class
 46 
 47 
            AssemblyName assemblyName 
=
 
new
 AssemblyName(
"
DynamicAssemblyExample
"
);
 48 
            AssemblyBuilder assemblyBuilder 
=
 AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
 49 
            ModuleBuilder moduleBuilder 
=
 assemblyBuilder.DefineDynamicModule(assemblyName.Name, assemblyName.Name 
+
 
"
.dll
"
);
 50 
 51 
            TypeBuilder typeBuilder 
=
 moduleBuilder.DefineType(
"
DynamicAssemblyExample.Calculate
"
, TypeAttributes.Public 
|
 TypeAttributes.Class
 52 
                , 
typeof
(
object
), 
new
 Type[] { 
typeof
(ICalculate) });
 53 
 54 
            FieldBuilder instanceField 
=
 typeBuilder.DefineField(
"
_instance
"
typeof
(ICalculate), FieldAttributes.Private);
 55 
 56 
            ConstructorBuilder constructorBuilder 
=
 typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, 
new
 Type[] { 
typeof
(ICalculate) });
 57 
 58 
            ILGenerator ilGenConstructor 
=
 constructorBuilder.GetILGenerator();
 59 
            ilGenConstructor.Emit(OpCodes.Ldarg_0);
 60 
            ilGenConstructor.Emit(OpCodes.Call, 
typeof
(
object
).GetConstructor(Type.EmptyTypes)); 
//
base.ctor()
 61 
            ilGenConstructor.Emit(OpCodes.Ldarg_0);
 62 
            ilGenConstructor.Emit(OpCodes.Ldarg_1);
 63 
            ilGenConstructor.Emit(OpCodes.Stfld, instanceField);
 64 
            ilGenConstructor.Emit(OpCodes.Ret);
 65 
 66 
            MethodInfo addMethodInfo 
=
 
typeof
(ICalculate).GetMethod(
"
Add
"
);
 67 
 68 
            MethodAttributes methodAttr 
=
 addMethodInfo.Attributes 
&
 
~
(MethodAttributes.Abstract);
 69 
 70 
            List
<
Type
>
 paramTypes 
=
 
new
 List
<
Type
>
();
 71 
 72 
            
foreach
 (ParameterInfo pInfo 
in
 addMethodInfo.GetParameters())
 73 
            {
 74 
                paramTypes.Add(pInfo.ParameterType);
 75 
            }
 76 
 77 
            MethodBuilder addMethod 
=
 typeBuilder.DefineMethod(addMethodInfo.Name, methodAttr,
 78 
                CallingConventions.Standard, addMethodInfo.ReturnType, paramTypes.ToArray());
 79 
 80 
            
//
writeline call
 81 
            MethodInfo writeLineMethod 
=
 
typeof
(Console).GetMethod(
"
WriteLine
"
new
 Type[] { 
typeof
(
string
) });
 82 
 83 
            ILGenerator ilGenAddMethod 
=
 addMethod.GetILGenerator();
 84 
 85 
 86 
            ilGenAddMethod.Emit(OpCodes.Ldstr, 
"
Before...
"
);
 87 
            ilGenAddMethod.Emit(OpCodes.Call, writeLineMethod);
 88 
 89 
            
//
每个实例方法都默认包含一个隐藏的参数,即第0个参数,它对应的是this指针,但静态方法没有隐藏的第0个参数
 90 
            ilGenAddMethod.Emit(OpCodes.Ldarg_0);
 91 
            ilGenAddMethod.Emit(OpCodes.Ldfld, instanceField);
 92 
 93 
            
 94 
            ilGenAddMethod.Emit(OpCodes.Ldarg_1);
//
a
 95 
            ilGenAddMethod.Emit(OpCodes.Ldarg_2);
//
b
 96 
            ilGenAddMethod.Emit(OpCodes.Callvirt, 
typeof
(ICalculate).GetMethod(
"
Add
"
));
//
a+b
 97 
 98 
            ilGenAddMethod.Emit(OpCodes.Ldstr, 
"
After...
"
);
 99 
            ilGenAddMethod.Emit(OpCodes.Call, writeLineMethod);
100 
101 
            
/*
102 
             * Console.WriteLine(this.GetType().FullName);
103 
             
*/
104 
            ilGenAddMethod.DeclareLocal(
typeof
(
int
));
105 
            ilGenAddMethod.Emit(OpCodes.Ldarg_0);
106 
            ilGenAddMethod.Emit(OpCodes.Callvirt, 
typeof
(
object
).GetMethod(
"
GetType
"
));
107 
            ilGenAddMethod.Emit(OpCodes.Callvirt, 
typeof
(Type).GetMethod(
"
get_FullName
"
));
108 
            ilGenAddMethod.Emit(OpCodes.Call, writeLineMethod);
109 
110 
111 
            ilGenAddMethod.Emit(OpCodes.Ret);
112 
113 
            proxyType 
=
 typeBuilder.CreateType();
114 
115 
            assemblyBuilder.Save(
"
DynamicAssemblyExample.dll
"
);
116 
            
#endregion
117 
118 
            ICalculate proxyImp 
=
 (ICalculate)proxyType.GetConstructor(
new
 Type[] { 
typeof
(ICalculate) })
119 
                .Invoke(
new
 
object
[] { 
new
 A() });
120 
121 
            proxyImp.Add(
10
20
);
122 
        }
123 
    }

 AOP的概念

  •Aspect Oriented Programming
  •AOP是OOP的延续,意思是面向切面编程
  •切面是指整体中的某个行为(功能)部分
  •目标:将与主逻辑无紧密关系的行为,从业务逻辑代码中分离出来
  •优点:当改变某个行为时,不会影响到业务逻辑,并且使代码进一步解耦
  •常用于日志记录,性能统计,安全控制,事务处理,异常处理等等
AOP的工作原理 
•AOP的关键是拦截正常的方法调用,即将需要额外附加的功能透明的“织入( Weave)”到这些方法中
•所谓“织入”简单的讲就是指将附件功能和目标的原有功能融合在一起,AOP像一台织布机,将两者天衣无缝的编织起来,织入是透明的
•在.Net中,AOP的织入方式有两种:

   静态织入:在编译阶段将附加逻辑写入代码中

   动态织入:在运行阶段将附加逻辑写入代码中 

  •静态织入:一般都需要扩展编译器的功能,优点是代码执行的效率高,缺点是实现者需要对虚拟机有很深的了解,而且修改代码之后都需要重新编译,目前,最著名的产品是:PostSharp
  •动态织入:不需要扩展编译器的功能,优点是在运行时自动生成代码,缺点是执行效率不高,需要额外的开销,目前,运用动态织入方法的产品较多,Castle.DynamicProxy是其中的经典之一

   动态织入的实现技术就是动态代理,由于静态织入存在局限性,一般来说,AOP框架实现方式首选动态织入,因此,AOP可以看作是动态代理发展的产物

 •Demo:AOP实践Castle.DynamicProxy

这是一个轻量级的,能为一个或多个接口或具体类创建动态代理的类库,或者称之为AOP类库内部机制是使用反射发出动态织入

拦截器( Interceptor)是其中的重要概念,用于截获方法的调用,增加新的逻辑,自定义拦截器必须实现IInterceptor接口或者继承内置的标准拦截器类StandardInterceptor拦截器对方法和属性都有效

典型应用:

   参数检验
   延迟加载(Lazy Loading)
典型代表:
   NHibernate

 

ExpandedBlockStart.gif
View Code
 1 
 
class
 Program
 2 
    {
 3 
        
static
 
void
 Main(
string
[] args)
 4 
        {
 5 
            DemoClassInterceptorTest.DoTest();
 6 
 7 
            
//
DemoInterfaceInterceptorTest.DoTest();
 8 
        }
 9 
    }
10 
public
 
interface
 IDemoInterface
11 
    {
12 
        
void
 Add(
int
 a, 
int
 b);
13 
    }
14 
15 
    
public
 
class
 DemoInterfaceClass : IDemoInterface
16 
    {
17 
        
#region
 DemoInterface 成员
18 
19 
        
public
 
void
 Add(
int
 a, 
int
 b)
20 
        {
21 
            Console.WriteLine(a 
+
 b);
22 
        }
23 
24 
        
#endregion
25 
    }
26 
27 
    
public
 
class
 DemoInterfaceInterceptor : StandardInterceptor
28 
    {
29 
        
protected
 
override
 
void
 PreProceed(IInvocation invocation)
30 
        {
31 
            Console.WriteLine(
"
PreProceed:{0}
"
, invocation.Method.ToString());
32 
        }
33 
34 
        
protected
 
override
 
void
 PostProceed(IInvocation invocation)
35 
        {
36 
            Console.WriteLine(
"
PostProceed:{0}
"
, invocation.Method.ToString());
37 
        }
38 
39 
        
protected
 
override
 
void
 PerformProceed(IInvocation invocation)
40 
        {
41 
            
base
.PerformProceed(invocation);
42 
        }
43 
    }
44 
45 
    
public
 
class
 DemoInterfaceInterceptorTest
46 
    {
47 
        
public
 
static
 
void
 DoTest()
48 
        {
49 
            DemoInterfaceClass realObj 
=
 
new
 DemoInterfaceClass();
50 
51 
            DemoInterfaceInterceptor interceptor 
=
 
new
 DemoInterfaceInterceptor();
52 
53 
            ProxyGenerator generator 
=
 
new
 ProxyGenerator();
54 
            IDemoInterface proxy
=
generator.CreateInterfaceProxyWithTargetInterface
<
IDemoInterface
>
(realObj, interceptor);
55 
            proxy.Add(
10
50
);
56 
        }
57 
    }

 

ExpandedBlockStart.gif
View Code
 1 
 
public
 
class
 DemoClass
 2 
    {
 3 
 4 
        
string
 _text;
 5 
        
public
 
virtual
 
string
 Text
 6 
        {
 7 
            
get
 8 
            {
 9 
                
return
 _text;
10 
            }
11 
            
set
12 
            {
13 
                _text 
=
 value;
14 
            }
15 
        }
16 
17 
        
public
 
virtual
 
void
 Add(
int
 a, 
int
 b)
18 
        {
19 
            Console.WriteLine(a 
+
 b);
20 
        }
21 
    }
22 
23 
    
class
 DemoClassInterceptor : IInterceptor
24 
    {
25 
        
#region
 IInterceptor 成员
26 
27 
        
///
 
<summary>
28 
        
///
 Intercepts the specified invocation.
29 
        
///
 
</summary>
30 
        
///
 
<param name="invocation">
The invocation.
</param>
31 
        
public
 
void
 Intercept(IInvocation invocation)
32 
        {
33 
            PreProceed(invocation);
34 
            invocation.Proceed();
35 
            PostProceed(invocation);
36 
        }
37 
38 
        
#endregion
39 
40 
        
public
 
void
 PreProceed(IInvocation invocation)
41 
        {
42 
            Console.WriteLine(
"
PreProceed 1 代理了:{0}
"
, invocation.Method.ToString());
43 
        }
44 
45 
        
public
 
void
 PostProceed(IInvocation invocation)
46 
        {
47 
            Console.WriteLine(
"
PostProceed 1 代理了:{0}
"
, invocation.Method.ToString());
48 
        }
49 
    }
50 
51 
    
class
 DemoClassInterceptor2 : IInterceptor
52 
    {
53 
        
#region
 IInterceptor 成员
54 
55 
        
///
 
<summary>
56 
        
///
 Intercepts the specified invocation.
57 
        
///
 
</summary>
58 
        
///
 
<param name="invocation">
The invocation.
</param>
59 
        
public
 
void
 Intercept(IInvocation invocation)
60 
        {
61 
            PreProceed(invocation);
62 
            invocation.Proceed();
63 
            PostProceed(invocation);
64 
        }
65 
66 
        
#endregion
67 
68 
        
public
 
void
 PreProceed(IInvocation invocation)
69 
        {
70 
            Console.WriteLine(
"
PreProceed 2 代理了:{0}
"
, invocation.Method.ToString());
71 
        }
72 
73 
        
public
 
void
 PostProceed(IInvocation invocation)
74 
        {
75 
            Console.WriteLine(
"
PostProceed 2 代理了:{0}
"
, invocation.Method.ToString());
76 
        }
77 
    }
78 
79 
    
class
 DemoClassInterceptorTest
80 
    {
81 
        
public
 
static
 
void
 DoTest()
82 
        {
83 
            ProxyGenerator generator 
=
 
new
 ProxyGenerator();
84 
            DemoClassInterceptor interceptor 
=
 
new
 DemoClassInterceptor();
85 
            DemoClassInterceptor2 interceptor2 
=
 
new
 DemoClassInterceptor2();
86 
            DemoClass obj 
=
 generator.CreateClassProxy
<
DemoClass
>
(interceptor, interceptor2);
87 
            obj.Text 
=
 
"
test
"
;
88 
            obj.Add(
10
20
);
89 
        }
90 
    }

 

转载地址:http://ridta.baihongyu.com/

你可能感兴趣的文章
iOS 多线程总结
查看>>
webpack是如何实现前端模块化的
查看>>
TCP的三次握手四次挥手
查看>>
关于redis的几件小事(六)redis的持久化
查看>>
webpack4+babel7+eslint+editorconfig+react-hot-loader 搭建react开发环境
查看>>
Maven 插件
查看>>
初探Angular6.x---进入用户编辑模块
查看>>
计算机基础知识复习
查看>>
【前端词典】实现 Canvas 下雪背景引发的性能思考
查看>>
大佬是怎么思考设计MySQL优化方案的?
查看>>
<三体> 给岁月以文明, 给时光以生命
查看>>
Android开发 - 掌握ConstraintLayout(九)分组(Group)
查看>>
springboot+logback日志异步数据库
查看>>
Typescript教程之函数
查看>>
Android 高效安全加载图片
查看>>
vue中数组变动不被监测问题
查看>>
3.31
查看>>
类对象定义 二
查看>>
收费视频网站Netflix:用户到底想要“点”什么?
查看>>
MacOS High Sierra 12 13系统转dmg格式
查看>>