实现.net下的动态代理 一文使用动态代理实现了 Ducking Typing,解决了文中的第一个问题,下面,向第二个问题进军——mixin。
实现.net下的动态代理 一文使用动态代理实现了 Ducking Typing,解决了文中的第一个问题,下面,向第二个问题进军——mixin。
一、应用场景
(1) 假定有一个接口TInterface,一个类B,类C。类B与类C分别实现了部分TInterface:
1
public interface TInterface
2
{
3
String A
{ get; }
4
String B(int a, int b);
5
}
6
7
public class ClassB
8
{
9
public String A
10
{
11
get
12
{
13
return String.Empty;
14
}
15
set
16
{ }
17
}
18
}
19
20
public class ClassC
21
{
22
public String B(int a, int b)
23
{
24
return (a + b).ToString();
25
}
26
}
假设b和c分别是B和C的一个实例,通过 TypeTemplate.Create<TInterface>(b,c) 方法将b和c包装一下,即可生成一个TInterface实例:
1
ClassB b = new ClassB();
2
ClassC c = new ClassC();
3
TInterface i2 = TypeTemplate.Create<TInterface>(b, c);
4
(2) 通过Mixin,我们还可以在运行时动态替换接口的指定方法或属性:
1
public interface Human
2
{
3
String Heart();
4
String Lung();
5
String Name();
6
}
7
8
public class ZhouBapi : Human
9
{
10
public String Heart()
{ return "好心"; }
11
public String Lung()
{ return "好肺"; }
12
public String Name()
{ return "周扒皮"; }
13
}
14
15
public class Huaidan
16
{
17
public String Heart()
{ return "狼心"; }
18
public String Lung()
{ return "狗肺"; }
19
}
20
21
class Program
22
{
23
static void Show(Human body)
24
{
25
Console.WriteLine(String.Format("我叫{0},我是{1}{2}", body.Name(), body.Heart(), body.Lung()));
26
}
27
28
static void ShowHuaidan(Human body)
29
{
30
Console.WriteLine(String.Format("{0},我看你是{1}{2}", body.Name(), body.Heart(), body.Lung()));
31
}
32
33
static void Main(string[] args)
34
{
35
Human zhou = new ZhouBapi();
36
Console.Write("周扒皮: ");
37
Show(zhou);
38
zhou = TypeTemplate.Create<Human>(new Huaidan(), zhou);
39
Console.Write("人民群众:");
40
ShowHuaidan(zhou);
41
Console.Read();
42
}
43
}
输出为:
周扒皮: 我叫周扒皮,我是好心好肺
人民群众:周扒皮,我看你是狼心狗肺
二、实现
以下是详细实现代码:

Code
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
using System.Reflection;
5
using System.Reflection.Emit;
6
7
namespace Orc.Generics
8

{
9
public sealed class TypeTemplate
10
{
11
public class ObjectContainer
12
{
13
private List<Object> Container = new List<object>();
14
private List<Type> TypeContainer = new List<Type>();
15
16
public ObjectContainer(Object[] objs, Type[] tlist)
17
{
18
Container.AddRange(objs);
19
TypeContainer.AddRange(tlist);
20
}
21
22
public Object Get(Int32 index)
23
{
24
if (index >= 0 && index < Container.Count)
25
return Container[index];
26
else
27
return null;
28
}
29
30
public Type GetType(Int32 index)
31
{
32
if (index >= 0 && index < TypeContainer.Count)
33
return TypeContainer[index];
34
else
35
return null;
36
}
37
38
public static MethodInfo GetGetMethodInfo()
39
{
40
MethodInfo[] mis = typeof(ObjectContainer).GetMethods(BindingFlags.Public | BindingFlags.Instance);
41
foreach (var mi in mis)
42
{
43
if (mi.Name == "Get") return mi;
44
}
45
return null;
46
}
47
}
48
49
private class MethodInfoHolder
50
{
51
public Int32 ObjectIndex
{ get; private set; }
52
public MethodInfo MethodInfo
{ get; private set; }
53
public Type ObjectType
{ get; private set; }
54
public MethodInfoHolder(MethodInfo pi, Int32 index, Type type)
55
{
56
MethodInfo = pi;
57
ObjectIndex = index;
58
ObjectType = type;
59
}
60
}
61
62
public delegate void Handler<TImple>(TImple imple) where TImple: class;
63
64
public static TInterface Create<TInterface, TImple>(TImple instance)
65
where TInterface : class
66
where TImple : class
67
{
68
Type type = DynamicTypeGen<TInterface>( new Object[]
{ instance }, new Type[]
{ instance.GetType()});
69
return Activator.CreateInstance(type, new ObjectContainer(new Object[]
{ instance }, new Type[]
{ instance.GetType() })) as TInterface;
70
}
71
72
public static TInterface Create<TInterface>(params Object[] impleInstances)
73
where TInterface : class
74
{
75
List<Type> tlist = new List<Type>();
76
foreach (var item in impleInstances)
77
{
78
tlist.Add(item.GetType());
79
}
80
Type type = DynamicTypeGen<TInterface>(impleInstances, tlist.ToArray());
81
return Activator.CreateInstance(type, new ObjectContainer( impleInstances, tlist.ToArray())) as TInterface;
82
}
83
84
public static TInterface CreateIntercepted<TInterface, TImple>(TImple instance, Handler<TImple> before, Handler<TImple> after)
85
where TInterface : class
86
where TImple : class
87
{
88
throw new NotImplementedException();
89
}
90
91
public static Type DynamicTypeGen<TInterface>(Object[] instances, Type[] typeList)
92
where TInterface: class
93
{
94
Type tInterface = typeof(TInterface);
95
96
PropertyInfo[] pisInterface = tInterface.GetProperties(BindingFlags.Public | BindingFlags.Instance);
97
MethodInfo[] misInterface = tInterface.GetMethods(BindingFlags.Public | BindingFlags.Instance);
98
List<MethodInfo> misInterfaceList = new List<MethodInfo>();
99
100
List<Type> tList = new List<Type>();
101
foreach (var obj in instances)
102
{
103
tList.Add(obj.GetType());
104
}
105
106
Type[] tArray = tList.ToArray();
107
108
foreach (var item in misInterface)
109
{
110
if (item.IsSpecialName == false) misInterfaceList.Add(item);
111
}
112
113
List<MethodInfoHolder> miHolderList = new List<MethodInfoHolder>();
114
for (int i = 0; i < tArray.Length; i++)
115
{
116
MethodInfo[] misImple = tArray[i].GetMethods(BindingFlags.Public | BindingFlags.Instance);
117
foreach (var item in misImple)
118
{
119
MethodInfoHolder h = new MethodInfoHolder(item, i, typeList[i]);
120
miHolderList.Add(h);
121
}
122
}
123
124
AssemblyName aName = new AssemblyName("Orc.Generics.DynamicTypes");
125
AssemblyBuilder ab =
126
AppDomain.CurrentDomain.DefineDynamicAssembly(
127
aName,
128
AssemblyBuilderAccess.RunAndSave);
129
130
ModuleBuilder mb =
131
ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");
132
133
TypeBuilder tb = mb.DefineType(GetDynamicTypeName<TInterface>(instances),
134
TypeAttributes.Public, null, new Type[]
{ tInterface });
135
FieldBuilder fbInstances = tb.DefineField(
136
"_container",
137
typeof(TypeTemplate.ObjectContainer),
138
FieldAttributes.Private);
139
140
ConstructorBuilder ctor1 = tb.DefineConstructor(
141
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName,
142
CallingConventions.Standard,
143
new Type[1]
{ typeof(TypeTemplate.ObjectContainer) });
144
145
ILGenerator ctor1IL = ctor1.GetILGenerator();
146
ctor1IL.Emit(OpCodes.Ldarg_0);
147
ctor1IL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
148
ctor1IL.Emit(OpCodes.Ldarg_0);
149
ctor1IL.Emit(OpCodes.Ldarg_1);
150
ctor1IL.Emit(OpCodes.Stfld, fbInstances);
151
ctor1IL.Emit(OpCodes.Ret);
152
153
foreach (var item in pisInterface)
154
{
155
MethodInfoHolder getMi = FindGetMethodInfo(miHolderList, item);
156
MethodInfoHolder setMi = FindSetMethodInfo(miHolderList, item);
157
CreateProperty(tb, fbInstances, item, getMi, setMi);
158
}
159
160
foreach (var item in misInterfaceList)
161
{
162
MethodInfoHolder instanceMi = FindMethodInfo(miHolderList, item);
163
CreateMethod(tb, fbInstances, item, instanceMi);
164
}
165
Type type = tb.CreateType();
166
ab.Save(aName.Name + ".dll");
167
return type;
168
}
169
170
private static MethodInfoHolder FindGetMethodInfo(IEnumerable<MethodInfoHolder> miList, PropertyInfo pi)
171
{
172
foreach (var item in miList)
173
{
174
if (item.MethodInfo.Name.Equals("get_" + pi.Name) && item.MethodInfo.IsSpecialName) return item;
175
}
176
177
return null;
178
}
179
180
private static MethodInfoHolder FindSetMethodInfo(IEnumerable<MethodInfoHolder> miList, PropertyInfo pi)
181
{
182
foreach (var item in miList)
183
{
184
if (item.MethodInfo.Name.Equals("set_" + pi.Name) && item.MethodInfo.IsSpecialName) return item;
185
}
186
187
return null;
188
}
189
190
private static MethodInfoHolder FindMethodInfo(IEnumerable<MethodInfoHolder> miList, MethodInfo mi)
191
{
192
foreach (var item in miList)
193
{
194
if (MethodInfoEqual(item.MethodInfo,mi)) return item;
195
}
196
197
return null;
198
}
199
200
private static Boolean MethodInfoEqual(MethodInfo mi1, MethodInfo mi2)
201
{
202
if (mi1.IsSpecialName == true || mi2.IsSpecialName == true) return false;
203
if (mi1.Name != mi2.Name) return false;
204
if (mi1.ReturnType != mi2.ReturnType) return false;
205
ParameterInfo[] pis1 = mi1.GetParameters();
206
ParameterInfo[] pis2 = mi2.GetParameters();
207
if (pis1.Length != pis2.Length) return false;
208
for (int i = 0; i < pis1.Length; i++)
209
{
210
ParameterInfo pi1 = pis1[i];
211
ParameterInfo pi2 = pis2[i];
212
if (pi1.ParameterType != pi2.ParameterType) return false;
213
}
214
return true;
215
}
216
217
private static void CreateProperty(TypeBuilder tb, FieldBuilder fbInstance, PropertyInfo pi, MethodInfoHolder getMi, MethodInfoHolder setMi)
218
{
219
String name = pi.Name;
220
Type type = pi.PropertyType;
221
222
PropertyBuilder pb = tb.DefineProperty(
223
name,
224
PropertyAttributes.HasDefault,
225
type,
226
null);
227
228
MethodAttributes getSetAttr = MethodAttributes.Public |
229
MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final ;
230
MethodBuilder mbGetAccessor = tb.DefineMethod(
231
"get_" + name,
232
getSetAttr,
233
type,
234
Type.EmptyTypes);
235
236
ILGenerator getIL = mbGetAccessor.GetILGenerator();
237
238
if (getMi == null)
239
{
240
getIL.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(new Type[]
{}));
241
getIL.Emit(OpCodes.Throw);
242
}
243
else
244
{
245
getIL.Emit(OpCodes.Ldarg_0);
246
getIL.Emit(OpCodes.Ldfld, fbInstance);
247
getIL.Emit(OpCodes.Ldc_I4, getMi.ObjectIndex);
248
getIL.Emit(OpCodes.Callvirt, ObjectContainer.GetGetMethodInfo());
249
getIL.Emit(OpCodes.Isinst, getMi.ObjectType);
250
getIL.Emit(OpCodes.Callvirt, getMi.MethodInfo);
251
getIL.Emit(OpCodes.Ret);
252
}
253
254
MethodBuilder mbSetAccessor = tb.DefineMethod(
255
"set_"+ name,
256
getSetAttr,
257
null,
258
new Type[]
{ type });
259
260
ILGenerator setIL = mbSetAccessor.GetILGenerator();
261
if (setMi == null)
262
{
263
setIL.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(new Type[]
{ }));
264
setIL.Emit(OpCodes.Throw);
265
}
266
else
267
{
268
setIL.Emit(OpCodes.Ldarg_0);
269
setIL.Emit(OpCodes.Ldfld, fbInstance);
270
setIL.Emit(OpCodes.Ldc_I4, setMi.ObjectIndex);
271
setIL.Emit(OpCodes.Callvirt, ObjectContainer.GetGetMethodInfo());
272
setIL.Emit(OpCodes.Isinst, setMi.ObjectType);
273
setIL.Emit(OpCodes.Ldarg_1);
274
setIL.Emit(OpCodes.Callvirt, setMi.MethodInfo);
275
setIL.Emit(OpCodes.Ret);
276
}
277
278
pb.SetGetMethod(mbGetAccessor);
279
pb.SetSetMethod(mbSetAccessor);
280
}
281
282
private static void CreateMethod(TypeBuilder tb, FieldBuilder fbInstance, MethodInfo mi, MethodInfoHolder instanceMi)
283
{
284
List<Type> paramTyleList = new List<Type>();
285
foreach(var item in mi.GetParameters())
286
paramTyleList.Add(item.ParameterType);
287
288
MethodBuilder mb = tb.DefineMethod(
289
mi.Name,
290
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
291
mi.ReturnType,
292
paramTyleList.ToArray());
293
294
ILGenerator il = mb.GetILGenerator();
295
if (instanceMi == null)
296
{
297
il.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(new Type[]
{ }));
298
il.Emit(OpCodes.Throw);
299
}
300
else
301
{
302
il.Emit(OpCodes.Ldarg_0);
303
il.Emit(OpCodes.Ldfld, fbInstance);
304
il.Emit(OpCodes.Ldc_I4, instanceMi.ObjectIndex);
305
il.Emit(OpCodes.Callvirt, ObjectContainer.GetGetMethodInfo());
306
il.Emit(OpCodes.Isinst, instanceMi.ObjectType);
307
switch (paramTyleList.Count)
308
{
309
case 0:
310
break;
311
case 1:
312
il.Emit(OpCodes.Ldarg_1);
313
break;
314
case 2:
315
il.Emit(OpCodes.Ldarg_1);
316
il.Emit(OpCodes.Ldarg_2);
317
break;
318
case 3:
319
il.Emit(OpCodes.Ldarg_1);
320
il.Emit(OpCodes.Ldarg_2);
321
il.Emit(OpCodes.Ldarg_3);
322
break;
323
default:
324
il.Emit(OpCodes.Ldarg_1);
325
il.Emit(OpCodes.Ldarg_2);
326
il.Emit(OpCodes.Ldarg_3);
327
328
Int32 sCount = Math.Min(paramTyleList.Count, 127);
329
for (int i = 4; i <= sCount; i++)
330
{
331
il.Emit(OpCodes.Ldarg_S, i);
332
}
333
334
for (int i = 128; i <= paramTyleList.Count; i++)
335
{
336
il.Emit(OpCodes.Ldarg, i);
337
}
338
339
break;
340
}
341
342
il.Emit(OpCodes.Callvirt, instanceMi.MethodInfo);
343
il.Emit(OpCodes.Ret);
344
}
345
}
346
347
private static String GetDynamicTypeName<TInterface>(params Object[] instances)
348
where TInterface : class
349
{
350
StringBuilder sb = new StringBuilder();
351
sb.Append("_DynamicTypes");
352
sb.Append(typeof(TInterface).ToString());
353
foreach (var obj in instances)
354
{
355
sb.Append("_");
356
sb.Append(obj.GetType().ToString());
357
}
358
return sb.ToString();
359
}
360
}
361
362
public interface TInterface
363
{
364
String A
{ get; }
365
String B(int a, int b);
366
}
367
368
public class ClassB
369
{
370
public String A
371
{
372
get
373
{
374
return String.Empty;
375
}
376
set
377
{ }
378
}
379
}
380
381
public class ClassC
382
{
383
public String B(int a, int b)
384
{
385
return (a + b).ToString();
386
}
387
}
388
389
public class ClassA
390
{
391
public String A
392
{
393
get
394
{
395
return String.Empty;
396
}
397
set
398
{ }
399
}
400
401
public String B(int a, int b)
402
{
403
return (a+b).ToString();
404
}
405
}
406
407
public class InterfaceImple_ClassA : TInterface
408
{
409
private TypeTemplate.ObjectContainer __container;
410
411
public InterfaceImple_ClassA(TypeTemplate.ObjectContainer container)
412
{
413
__container = container;
414
}
415
416
public String A
417
{
418
get
{ return (__container.Get(1) as ClassA).A; }
419
set
{ (__container.Get(1) as ClassA).A = value; }
420
}
421
422
public String B(int a, int b)
423
{
424
return (__container.Get(1) as ClassA).B(a, b);
425
}
426
}
427
428
public class InterfaceImple_ClassA_Factory
429
{
430
public readonly String Name = "InterfaceImple_ClassA_Factory";
431
public InterfaceImple_ClassA Create(ClassA a)
432
{
433
return null;
434
// return new InterfaceImple_ClassA(new Object[] {a});
435
}
436
}
437
}
438
测试代码:
1
[TestMethod]
2
public void TestCreate()
3
{
4
ClassA a = new ClassA();
5
TInterface i1 = TypeTemplate.Create<TInterface, ClassA>(a);
6
Assert.AreNotEqual(null, i1);
7
Assert.AreEqual("3", i1.B(1, 2));
8
Assert.AreEqual(String.Empty, i1.A);
9
10
ClassB b = new ClassB();
11
ClassC c = new ClassC();
12
TInterface i2 = TypeTemplate.Create<TInterface>(b, c);
13
Assert.AreNotEqual(null, i2);
14
Assert.AreEqual("3", i2.B(1, 2));
15
Assert.AreEqual(String.Empty, i2.A);
16
}
17
三、说明:
(1)通过上述方法可以很方便的创建对现有实例的Wrapper,使其适应一个新的接口;
(2)TypeTemplate.Create<TInterface>(params Object[] impleInstances) 排位在前的 impleInstance 的接口方法/属性将掩盖它后面的 impleInstance 的接口方法/属性,这样可以在运行时动态改变接口的行为。
(3)这种MixIn方案比不上动态语言的MixIn,主要是必须要有一个interface,才能MixIn。如果能将interface也根据被代理的对象的行为动态生成,那就很爽了。怎么实现,是一个问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义