一、动态代理可以解决哪些问题
本文描述的动态代理可以解决以下问题:
问题1:接口约束问题
场景A:ComboBox类与ToolStripComboBox类的行为大部分相似,它们却不共享某个粒度较大的接口,以至于对这两个类的操作代码难以公用。
场景B:在泛型程序中,我们必需为泛型类型声明一个接口约束,才能使用该类型所对应接口约束的方法与属性。这样以来有一个问题:存在接口A,类型B,A中的所有属性和方法签名B都有,但B不是A的实现,不能由B转换为A。而由于某些原因,我们无法获得B的代码或者虽然能够获得B的代码,却由于种种考虑不能更改B的代码;
大多数情况下,可以新写一个类C,使类C继承自B,再让C实现接口A。然而,其一,代码量较大;其二,当B为Sealed时不能继承;其三:不方便使用继承(如:继承后,IDE中的设计器无法给新类提供支持)。
此时,我们希望动态代理能解决这个问题:
假定我们有一个接口:
1
public interface TInterface
2
{
3
String A
{ get; }
4
String B(Object a, Object b, Object c, Object d, Object e);
5
}
6
有一个类:
1
public class ClassA
2
{
3
public String A
4
{
5
get
6
{
7
return String.Empty;
8
}
9
}
10
11
public String B(Object a, Object b, Object c, Object d, Object e)
12
{
13
return String.Empty;
14
}
15
}
16
17
我们需要这个动态代理类(假定为 TypeTemplate)提供一个方法,能够方便的生成一个代理类实例,将ClassA的实例包装一下,转变为 TInterface 的实例:
1
public static TInterface Create<TInterface, TImple>(TImple instance)
2
where TInterface : class
3
where TImple : class
4
{
5
……
6
}
7
该方法生成一个实现TInterface的动态类的实例。对于TInterface中的每一个属性或方法,该实例直接调用instance实例中具有同样签名的属性或方法,如果没有匹配的属性或方法,则抛出NotImplementedException异常。
问题2:快速生成现有实例类的Wrapper
场景C:假定接口TInterface有10个方法,类TImple中有9个方法与TInterface对应,为了实现TInterface,需要新写一个Wrapper类。最方便的写法是令Wrapper继承自TImple且实现接口TInterface,Wrapper只需新添实现那个未实现的方法即可。然而,如前面所述,很多情况下使用继承不是最佳选择。不用继承的话,则需要Wrapper类实现TInterface的全部10个方法,枯燥又乏味。
此时,我们期待存在这样一种动态代理:它能够将几个实例B,C,D一起打包,使它适合接口A。这样一来,针对场景C,我们只需要写一个简单的Wrapper类,实现那个未实现的方法,然后与TImple实例一起由动态代理工厂打包生成一个新的代理类实例即可。
即:我们需要动态代理工厂TypeTemplate能够提供以下方法:
1
public static TInterface Create<TInterface>(TInterface instance, params Object[] impleInstances)
2
where TInterface : class
3
{
4
…
5
}
6
该方法生成一个实现TInterface的类实例。对于TInterface中的每一个属性或方法,该实例依次从impleInstances中寻找具有同样签名的属性或方法,如果没有匹配的属性或方法,则抛出NotImplementedException异常。
问题3:AOP应用
场景D:当需要对方法进行拦截时我们需要动态代理。
AOP是动态代理最经典的应用,无需赘述。
这种情况下,我们需要 TypeTemplate 类提供以下的方法向代理类中加入钩子:
1
public delegate void Handler<TImple>(TImple imple) where TImple: class;
2
3
public static TInterface CreateIntercepted<TInterface, TImple>(TImple instance, Handler<TImple> before, Handler<TImple> after)
4
where TInterface : class
5
where TImple : class
6
{
7
…
8
}
9
二、实现
下面来实现动态代理类工厂TypeTemplate。由于时间有限,只实现 static TInterface Create<TInterface, TImple>(TImple instance) 方法原型。其它几个静态方法可以用类似的方式实现。
实现思路:
对于问题1中的接口TInterface和类ClassA,通过Emit生成如下类型InterfaceImple_ClassA的IL代码。
1
public class InterfaceImple_ClassA : TInterface
2
{
3
private ClassA __wrappedInstance;
4
5
public InterfaceImple_ClassA(ClassA instance)
6
{
7
__wrappedInstance = instance;
8
}
9
10
public String A
11
{
12
get
{ return __wrappedInstance.A; }
13
set
{ throw new NotImplementedException(); }
14
}
15
16
public String B(Object a, Object b, Object c, Object d, Object e)
17
{
18
return __wrappedInstance.B(a,b,c,d,e);
19
}
20
}
21
22
假定生成上面这个类型的方法为:
1
public static Type DynamicTypeGen<TInterface, TImple>()
2
where TInterface: class where TImple : class
3
4
则可用Activator轻松生成动态代理类实例:
1
public static TInterface Create<TInterface, TImple>(TImple instance)
2
where TInterface : class
3
where TImple : class
4
{
5
Type type = DynamicTypeGen<TInterface, TImple>();
6
return Activator.CreateInstance(type, instance) as TInterface;
7
}
8
下面是具体代码:

Code
1
public sealed class TypeTemplate
2
{
3
public delegate void Handler<TImple>(TImple imple) where TImple: class;
4
5
public static TInterface Create<TInterface, TImple>(TImple instance)
6
where TInterface : class
7
where TImple : class
8
{
9
Type type = DynamicTypeGen<TInterface, TImple>();
10
return Activator.CreateInstance(type, instance) as TInterface;
11
}
12
13
public static TInterface Create<TInterface>(TInterface instance, params Object[] impleInstances)
14
where TInterface : class
15
{
16
throw new NotImplementedException();
17
}
18
19
public static TInterface CreateIntercepted<TInterface, TImple>(TImple instance, Handler<TImple> before, Handler<TImple> after)
20
where TInterface : class
21
where TImple : class
22
{
23
throw new NotImplementedException();
24
}
25
26
public static Type DynamicTypeGen<TInterface, TImple>()
27
where TInterface: class where TImple : class
28
{
29
Type tInterface = typeof(TInterface);
30
Type tImple = typeof(TImple);
31
32
PropertyInfo[] pisInterface = tInterface.GetProperties(BindingFlags.Public | BindingFlags.Instance);
33
MethodInfo[] misInterface = tInterface.GetMethods(BindingFlags.Public | BindingFlags.Instance);
34
List<MethodInfo> misInterfaceList = new List<MethodInfo>();
35
foreach (var item in misInterface)
36
{
37
if (item.IsSpecialName == false) misInterfaceList.Add(item);
38
}
39
40
MethodInfo[] misImple = tImple.GetMethods(BindingFlags.Public | BindingFlags.Instance);
41
AssemblyName aName = new AssemblyName("Orc.Generics.DynamicTypes");
42
AssemblyBuilder ab =
43
AppDomain.CurrentDomain.DefineDynamicAssembly(
44
aName,
45
AssemblyBuilderAccess.RunAndSave);
46
ModuleBuilder mb =
47
ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");
48
TypeBuilder tb = mb.DefineType(GetDynamicTypeName<TInterface, TImple>(),
49
TypeAttributes.Public, null, new Type[]
{ tInterface });
50
FieldBuilder fbInstance = tb.DefineField(
51
"__wrappedInstance",
52
tImple,
53
FieldAttributes.Private);
54
55
ConstructorBuilder ctor1 = tb.DefineConstructor(
56
MethodAttributes.Public,
57
CallingConventions.Standard,
58
new Type[]
{tImple});
59
60
ILGenerator ctor1IL = ctor1.GetILGenerator();
61
ctor1IL.Emit(OpCodes.Ldarg_0);
62
ctor1IL.Emit(OpCodes.Call,
63
typeof(object).GetConstructor(Type.EmptyTypes));
64
ctor1IL.Emit(OpCodes.Ldarg_0);
65
ctor1IL.Emit(OpCodes.Ldarg_1);
66
ctor1IL.Emit(OpCodes.Stfld, fbInstance);
67
ctor1IL.Emit(OpCodes.Ret);
68
69
foreach (var item in pisInterface)
70
{
71
MethodInfo getMi = FindGetMethodInfo(misImple, item);
72
MethodInfo setMi = FindSetMethodInfo(misImple, item);
73
CreateProperty(tb, fbInstance, item, getMi, setMi);
74
}
75
76
foreach (var item in misInterfaceList)
77
{
78
MethodInfo instanceMi = FindMethodInfo(misImple, item);
79
CreateMethod(tb, fbInstance, item, instanceMi);
80
}
81
82
return tb.CreateType();
83
}
84
85
private static MethodInfo FindGetMethodInfo(MethodInfo[] miList, PropertyInfo pi)
86
{
87
foreach (var item in miList)
88
{
89
if (item.Name.Equals("get_" + pi.Name) && item.IsSpecialName) return item;
90
}
91
92
return null;
93
}
94
95
private static MethodInfo FindSetMethodInfo(MethodInfo[] miList, PropertyInfo pi)
96
{
97
foreach (var item in miList)
98
{
99
if (item.Name.Equals("set_" + pi.Name) && item.IsSpecialName) return item;
100
}
101
102
return null;
103
}
104
105
private static MethodInfo FindMethodInfo(MethodInfo[] miList, MethodInfo mi)
106
{
107
foreach (var item in miList)
108
{
109
if (item.Equals(mi)) return item;
110
}
111
112
return null;
113
}
114
115
private static void CreateProperty(TypeBuilder tb, FieldBuilder fbInstance, PropertyInfo pi, MethodInfo getMi, MethodInfo setMi)
116
{
117
String name = pi.Name;
118
Type type = pi.PropertyType;
119
120
PropertyBuilder pb = tb.DefineProperty(
121
name,
122
PropertyAttributes.HasDefault,
123
type,
124
null);
125
126
MethodAttributes getSetAttr = MethodAttributes.Public |
127
MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final ;
128
MethodBuilder mbGetAccessor = tb.DefineMethod(
129
"get_" + name,
130
getSetAttr,
131
type,
132
Type.EmptyTypes);
133
134
ILGenerator getIL = mbGetAccessor.GetILGenerator();
135
if (getMi == null)
136
{
137
getIL.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(new Type[]
{}));
138
getIL.Emit(OpCodes.Throw);
139
}
140
else
141
{
142
getIL.Emit(OpCodes.Ldarg_0);
143
getIL.Emit(OpCodes.Ldfld, fbInstance);
144
getIL.Emit(OpCodes.Callvirt, getMi);
145
getIL.Emit(OpCodes.Ret);
146
}
147
148
MethodBuilder mbSetAccessor = tb.DefineMethod(
149
"set_"+ name,
150
getSetAttr,
151
null,
152
new Type[]
{ type });
153
154
ILGenerator setIL = mbSetAccessor.GetILGenerator();
155
if (setMi == null)
156
{
157
setIL.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(new Type[]
{ }));
158
setIL.Emit(OpCodes.Throw);
159
}
160
else
161
{
162
setIL.Emit(OpCodes.Ldarg_0);
163
setIL.Emit(OpCodes.Ldfld, fbInstance);
164
setIL.Emit(OpCodes.Ldarg_1);
165
setIL.Emit(OpCodes.Callvirt, setMi);
166
setIL.Emit(OpCodes.Ret);
167
}
168
169
pb.SetGetMethod(mbGetAccessor);
170
pb.SetSetMethod(mbSetAccessor);
171
}
172
173
private static void CreateMethod(TypeBuilder tb, FieldBuilder fbInstance, MethodInfo mi, MethodInfo instanceMi)
174
{
175
List<Type> paramTyleList = new List<Type>();
176
foreach(var item in mi.GetParameters())
177
paramTyleList.Add(item.ParameterType);
178
179
MethodBuilder mb = tb.DefineMethod(
180
mi.Name,
181
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
182
mi.ReturnType,
183
paramTyleList.ToArray());
184
185
ILGenerator il = mb.GetILGenerator();
186
if (instanceMi == null)
187
{
188
il.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(new Type[]
{ }));
189
il.Emit(OpCodes.Throw);
190
}
191
else
192
{
193
il.Emit(OpCodes.Ldarg_0);
194
il.Emit(OpCodes.Ldfld, fbInstance);
195
switch (paramTyleList.Count)
196
{
197
case 0:
198
break;
199
case 1:
200
il.Emit(OpCodes.Ldarg_1);
201
break;
202
case 2:
203
il.Emit(OpCodes.Ldarg_1);
204
il.Emit(OpCodes.Ldarg_2);
205
break;
206
case 3:
207
il.Emit(OpCodes.Ldarg_1);
208
il.Emit(OpCodes.Ldarg_2);
209
il.Emit(OpCodes.Ldarg_3);
210
break;
211
default:
212
il.Emit(OpCodes.Ldarg_1);
213
il.Emit(OpCodes.Ldarg_2);
214
il.Emit(OpCodes.Ldarg_3);
215
216
Int32 sCount = Math.Min(paramTyleList.Count, 127);
217
for (int i = 4; i <= sCount; i++)
218
{
219
il.Emit(OpCodes.Ldarg_S, i);
220
}
221
222
for (int i = 128; i <= paramTyleList.Count; i++)
223
{
224
il.Emit(OpCodes.Ldarg, i);
225
}
226
227
break;
228
}
229
230
il.Emit(OpCodes.Callvirt, instanceMi);
231
il.Emit(OpCodes.Ret);
232
}
233
}
234
235
private static String GetDynamicTypeName<TInterface, TImple>()
236
where TInterface : class
237
where TImple : class
238
{
239
return "_DynamicTypes" + typeof(TInterface).ToString() + "_" + typeof(TImple);
240
}
241
}
242
243
三、说明
1 上文只是 TypeTemplate的原型实现,我只进行了简单的单元测试,没有针对全部可能遇见的情况进行测试;在功能上,未生成event的动态代理;
2 static TInterface Create<TInterface>(TInterface instance, params Object[] impleInstances) 这个方法生成的代理类最好继承一个特殊接口,通过该接口能够接入被代理的实例;
3 如果第一部分所述的三个静态方法全部实现了的话,将是一个非常强大的代理工厂;
4 代理类实例的性能接近于直接调用相关方法或属性的性能,性能极佳;
5 代理类实例的生成是通过反射生成的,在性能上有很大的提升空间。可以通过emit动态生成一个工厂类。如,针对上面的ClassA,生成如下工厂类:
1
public class InterfaceImple_ClassA_Factory
2
{
3
public readonly String Name = "InterfaceImple_ClassA_Factory";
4
public InterfaceImple_ClassA Create(ClassA a)
5
{
6
return new InterfaceImple_ClassA(a);
7
}
8
}
9
然后通过反射生成以上工厂类的实例,缓存住。当需要生成新的动态代理实例时,从缓存中查找对应的工厂,生成具体的代理类。
原文地址