forked from ServiceStack/ServiceStack.Text
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDynamicProxy.cs
More file actions
132 lines (110 loc) · 4.46 KB
/
DynamicProxy.cs
File metadata and controls
132 lines (110 loc) · 4.46 KB
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using System;
using System.Linq;
using System.Reflection;
#if !SILVERLIGHT && !MONOTOUCH
using System.Reflection.Emit;
namespace ServiceStack.Text {
public static class DynamicProxy {
public static T GetInstanceFor<T> () {
return (T)GetInstanceFor(typeof(T));
}
static readonly ModuleBuilder ModuleBuilder;
static readonly AssemblyBuilder DynamicAssembly;
public static object GetInstanceFor (Type targetType) {
lock (DynamicAssembly)
{
var constructedType = DynamicAssembly.GetType(ProxyName(targetType)) ?? GetConstructedType(targetType);
var instance = Activator.CreateInstance(constructedType);
return instance;
}
}
static string ProxyName(Type targetType)
{
return targetType.Name + "Proxy";
}
static DynamicProxy () {
var assemblyName = new AssemblyName("DynImpl");
DynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder = DynamicAssembly.DefineDynamicModule("DynImplModule");
}
static Type GetConstructedType (Type targetType) {
var typeBuilder = ModuleBuilder.DefineType(targetType.Name + "Proxy", TypeAttributes.Public);
var ctorBuilder = typeBuilder.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
new Type[] { });
var ilGenerator = ctorBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ret);
IncludeType(targetType, typeBuilder);
foreach (var face in targetType.GetInterfaces())
IncludeType(face, typeBuilder);
return typeBuilder.CreateType();
}
static void IncludeType (Type typeOfT, TypeBuilder typeBuilder) {
var methodInfos = typeOfT.GetMethods();
foreach (var methodInfo in methodInfos) {
if (methodInfo.Name.StartsWith("set_")) continue; // we always add a set for a get.
if (methodInfo.Name.StartsWith("get_")) {
BindProperty(typeBuilder, methodInfo);
} else {
BindMethod(typeBuilder, methodInfo);
}
}
typeBuilder.AddInterfaceImplementation(typeOfT);
}
static void BindMethod (TypeBuilder typeBuilder, MethodInfo methodInfo) {
var methodBuilder = typeBuilder.DefineMethod(
methodInfo.Name,
MethodAttributes.Public | MethodAttributes.Virtual,
methodInfo.ReturnType,
methodInfo.GetParameters().Select(p => p.GetType()).ToArray()
);
var methodILGen = methodBuilder.GetILGenerator();
if (methodInfo.ReturnType == typeof(void)) {
methodILGen.Emit(OpCodes.Ret);
} else {
if (methodInfo.ReturnType.IsValueType || methodInfo.ReturnType.IsEnum) {
MethodInfo getMethod = typeof(Activator).GetMethod("CreateInstance",
new[] { typeof(Type) });
LocalBuilder lb = methodILGen.DeclareLocal(methodInfo.ReturnType);
methodILGen.Emit(OpCodes.Ldtoken, lb.LocalType);
methodILGen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
methodILGen.Emit(OpCodes.Callvirt, getMethod);
methodILGen.Emit(OpCodes.Unbox_Any, lb.LocalType);
} else {
methodILGen.Emit(OpCodes.Ldnull);
}
methodILGen.Emit(OpCodes.Ret);
}
typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);
}
public static void BindProperty (TypeBuilder typeBuilder, MethodInfo methodInfo) {
// Backing Field
string propertyName = methodInfo.Name.Replace("get_", "");
Type propertyType = methodInfo.ReturnType;
FieldBuilder backingField = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
//Getter
MethodBuilder backingGet = typeBuilder.DefineMethod("get_" + propertyName, MethodAttributes.Public |
MethodAttributes.SpecialName | MethodAttributes.Virtual |
MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getIl = backingGet.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, backingField);
getIl.Emit(OpCodes.Ret);
//Setter
MethodBuilder backingSet = typeBuilder.DefineMethod("set_" + propertyName, MethodAttributes.Public |
MethodAttributes.SpecialName | MethodAttributes.Virtual |
MethodAttributes.HideBySig, null, new[] { propertyType });
ILGenerator setIl = backingSet.GetILGenerator();
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, backingField);
setIl.Emit(OpCodes.Ret);
// Property
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, null);
propertyBuilder.SetGetMethod(backingGet);
propertyBuilder.SetSetMethod(backingSet);
}
}
}
#endif