Castle DynamicProxy动态生成透明代理类型,
实体不需要继承MarshalByRef、ContextBoundObject便可以实现代理类
基于透明代理的功能,可以实现对方法调用的拦截处理,例如NHibernate用它实现延迟加载
DP的使用非常简单,内部没有使用反射,而是采用Emit、委托等方式生成代理类型,调用真实类的方法,性能方面也没有太多损失
基本示例
引用的命名空间:
using
Castle.Core.Interceptor;
using
Castle.DynamicProxy;
|
1
2
|
using
Castle.Core.Interceptor;
using
Castle.DynamicProxy;
|
1
2
3
4
5
6
7
8
9
|
public
class
SimpleSamepleEntity
{
public
virtual
string
Name { get ; set ; }
public
virtual
int
Age { get ; set ; }
public
override
string
ToString()
{
return
string .Format( "{{ Name: \"{0}\", Age: {1} }}" , this .Name, this .Age);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
public
class
CallingLogInterceptor : IInterceptor
{
private
int
_indent = 0;
private
void
PreProceed(IInvocation invocation)
{
if
( this ._indent > 0)
Console.Write( " " .PadRight( this ._indent * 4, ' ' ));
this ._indent++;
Console.Write( "Intercepting: "
+ invocation.Method.Name + "(" );
if
(invocation.Arguments != null
&& invocation.Arguments.Length > 0)
for
( int
i = 0; i < invocation.Arguments.Length; i++)
{
if
(i != 0) Console.Write( ", " );
Console.Write(invocation.Arguments[i] == null
? "null"
: invocation.Arguments[i].GetType() == typeof ( string )
? "\""
+ invocation.Arguments[i].ToString() + "\""
: invocation.Arguments[i].ToString());
}
Console.WriteLine( ")" );
}
private
void
PostProceed(IInvocation invocation)
{
this ._indent--;
}
public
void
Intercept(IInvocation invocation)
{
this .PreProceed(invocation);
invocation.Proceed();
this .PostProceed(invocation);
}
}
|
1
2
3
4
5
6
7
8
|
ProxyGenerator generator = new
ProxyGenerator();
CallingLogInterceptor interceptor = new
CallingLogInterceptor();
SimpleSamepleEntity entity = generator.CreateClassProxy<SimpleSamepleEntity>(interceptor);
entity.Name = "Richie" ;
entity.Age = 50;
Console.WriteLine( "The entity is: "
+ entity);
Console.WriteLine( "Type of the entity: "
+ entity.GetType().FullName);
Console.ReadKey();
|
1
2
3
4
5
6
7
8
|
public
class
SimpleLogInterceptor : IInterceptor
{
public
void
Intercept(IInvocation invocation)
{
Console.WriteLine( ">>"
+ invocation.Method.Name);
invocation.Proceed();
}
}
|
1
2
3
4
5
6
7
8
9
|
ProxyGenerator generator = new
ProxyGenerator();
SimpleSamepleEntity entity = generator.CreateClassProxy<SimpleSamepleEntity>(
new
SimpleLogInterceptor(),
new
CallingLogInterceptor());
entity.Name = "Richie" ;
entity.Age = 50;
Console.WriteLine( "The entity is: "
+ entity);
Console.WriteLine( "Type of the entity: "
+ entity.GetType().FullName);
Console.ReadKey();
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public
class
InterceptorSelector : IInterceptorSelector
{
public
IInterceptor[] SelectInterceptors(Type type, MethodInfo method, IInterceptor[] interceptors)
{
if
(method.Name.StartsWith( "set_" )) return
interceptors;
else
return
interceptors.Where(i => i is
CallingLogInterceptor).ToArray<IInterceptor>();
}
}
public
class
InterceptorFilter : IProxyGenerationHook
{
public
bool
ShouldInterceptMethod(Type type, MethodInfo memberInfo)
{
return
memberInfo.IsSpecialName &&
(memberInfo.Name.StartsWith( "set_" ) || memberInfo.Name.StartsWith( "get_" ));
}
public
void
NonVirtualMemberNotification(Type type, MemberInfo memberInfo)
{
}
public
void
MethodsInspected()
{
}
}
|
1
2
3
4
5
6
7
8
9
10
|
ProxyGenerator generator = new
ProxyGenerator();
var options = new
ProxyGenerationOptions( new
InterceptorFilter()) { Selector = new
InterceptorSelector() };
SimpleSamepleEntity entity = generator.CreateClassProxy<SimpleSamepleEntity>(
options,
new
SimpleLogInterceptor(), new
CallingLogInterceptor());
entity.Name = "Richie" ;
entity.Age = 50;
Console.WriteLine( "The entity is: "
+ entity);
Console.WriteLine( "Type of the entity: "
+ entity.GetType().FullName);
Console.ReadKey();
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public
interface
IStorageNode
{
bool
IsDead { get ; set ; }
void
Save( string
message);
}
public
class
StorageNode : IStorageNode
{
private
string
_name;
public
StorageNode( string
name)
{
this ._name = name;
}
public
bool
IsDead { get ; set ; }
public
void
Save( string
message)
{
Console.WriteLine( string .Format( "\"{0}\" was saved to {1}" , message, this ._name));
}
}
public
class
DualNodeInterceptor : IInterceptor
{
private
IStorageNode _slave;
public
DualNodeInterceptor(IStorageNode slave)
{
this ._slave = slave;
}
public
void
Intercept(IInvocation invocation)
{
IStorageNode master = invocation.InvocationTarget as
IStorageNode;
if
(master.IsDead)
{
IChangeProxyTarget cpt = invocation as
IChangeProxyTarget;
//将被代理对象master更换为slave
cpt.ChangeProxyTarget( this ._slave);
//测试中恢复master的状态,以便看到随后的调用仍然使用master这一效果
master.IsDead = false ;
}
invocation.Proceed();
}
}
|
1
2
3
4
5
6
7
8
9
10
|
ProxyGenerator generator = new
ProxyGenerator();
IStorageNode node = generator.CreateInterfaceProxyWithTargetInterface<IStorageNode>(
new
StorageNode( "master" )
, new
DualNodeInterceptor( new
StorageNode( "slave" ))
, new
CallingLogInterceptor());
node.Save( "my message" ); //应该调用master对象
node.IsDead = true ;
node.Save( "my message" ); //应该调用slave对象
node.Save( "my message" ); //应该调用master对象
Console.ReadKey();
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public
interface
InterfaceA
{
void
ActionA();
}
public
class
ClassA : InterfaceA
{
public
void
ActionA()
{
Console.WriteLine( "I'm from ClassA" );
}
}
public
class
ClassB
{
public
virtual
void
ActionB()
{
Console.WriteLine( "I'm from ClassB" );
}
}
|
1
2
3
4
5
6
7
8
|
ProxyGenerator generator = new
ProxyGenerator();
var options = new
ProxyGenerationOptions();
options.AddMixinInstance( new
ClassA());
ClassB objB = generator.CreateClassProxy<ClassB>(options, new
CallingLogInterceptor());
objB.ActionB();
InterfaceA objA = objB as
InterfaceA;
objA.ActionA();
Console.ReadKey();
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
var scope = new
ModuleScope(
true ,
ModuleScope.DEFAULT_ASSEMBLY_NAME,
ModuleScope.DEFAULT_FILE_NAME,
"DynamicProxyTest.Proxies" ,
"DynamicProxyTest.Proxies.dll" );
var builder = new
DefaultProxyBuilder(scope);
var generator = new
ProxyGenerator(builder);
var options = new
ProxyGenerationOptions( new
InterceptorFilter())
{
Selector = new
InterceptorSelector()
};
SimpleSamepleEntity entity = generator.CreateClassProxy<SimpleSamepleEntity>(
options,
new
SimpleLogInterceptor(), new
CallingLogInterceptor());
IStorageNode node = generator.CreateInterfaceProxyWithTargetInterface<IStorageNode>(
new
StorageNode( "master" )
, new
DualNodeInterceptor( new
StorageNode( "slave" ))
, new
CallingLogInterceptor());
options = new
ProxyGenerationOptions();
options.AddMixinInstance( new
ClassA());
ClassB objB = generator.CreateClassProxy<ClassB>(options, new
CallingLogInterceptor());
scope.SaveAssembly( false );
|