comparison Source/TypeBuilder/Builders/InstanceTypeBuilder.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:f990fcb411a9
1 using System;
2 using System.Reflection;
3 using System.Reflection.Emit;
4
5 using BLToolkit.Properties;
6 using BLToolkit.Reflection;
7 using BLToolkit.Reflection.Emit;
8
9 namespace BLToolkit.TypeBuilder.Builders
10 {
11 class InstanceTypeBuilder : DefaultTypeBuilder
12 {
13 public InstanceTypeBuilder(Type instanceType, bool isObjectHolder)
14 {
15 _instanceType = instanceType;
16 _isObjectHolder = isObjectHolder;
17 }
18
19 public InstanceTypeBuilder(Type propertyType, Type instanceType, bool isObjectHolder)
20 {
21 _propertyType = propertyType;
22 _instanceType = instanceType;
23 _isObjectHolder = isObjectHolder;
24 }
25
26 private readonly bool _isObjectHolder;
27
28 private readonly Type _propertyType;
29 public Type PropertyType
30 {
31 get { return _propertyType; }
32 }
33
34 private readonly Type _instanceType;
35 public Type InstanceType
36 {
37 get { return _instanceType; }
38 }
39
40 public override bool IsApplied(BuildContext context, AbstractTypeBuilderList builders)
41 {
42 if (context == null) throw new ArgumentNullException("context");
43
44 return
45 base.IsApplied(context, builders) &&
46 context.CurrentProperty != null &&
47 context.CurrentProperty.GetIndexParameters().Length == 0 &&
48 (PropertyType == null ||
49 TypeHelper.IsSameOrParent(PropertyType, context.CurrentProperty.PropertyType));
50 }
51
52 protected override Type GetFieldType()
53 {
54 return InstanceType;
55 }
56
57 protected override Type GetObjectType()
58 {
59 return IsObjectHolder? Context.CurrentProperty.PropertyType: base.GetObjectType();
60 }
61
62 protected override bool IsObjectHolder
63 {
64 get { return _isObjectHolder && Context.CurrentProperty.PropertyType.IsClass; }
65 }
66
67 protected override void BuildAbstractGetter()
68 {
69 var field = GetField();
70 var emit = Context.MethodBuilder.Emitter;
71 var propertyType = Context.CurrentProperty.PropertyType;
72 var getter = GetGetter();
73
74 if (InstanceType.IsValueType) emit.ldarg_0.ldflda(field);
75 else emit.ldarg_0.ldfld (field);
76
77 Type memberType;
78
79 if (getter is PropertyInfo)
80 {
81 var pi = ((PropertyInfo)getter);
82
83 if (InstanceType.IsValueType) emit.call (pi.GetGetMethod());
84 else emit.callvirt(pi.GetGetMethod());
85
86 memberType = pi.PropertyType;
87 }
88 else if (getter is FieldInfo)
89 {
90 var fi = (FieldInfo)getter;
91
92 emit.ldfld(fi);
93
94 memberType = fi.FieldType;
95 }
96 else
97 {
98 var mi = (MethodInfo)getter;
99 var pi = mi.GetParameters();
100
101 for (var k = 0; k < pi.Length; k++)
102 {
103 var p = pi[k];
104
105 if (p.IsDefined(typeof(ParentAttribute), true))
106 {
107 // Parent - set this.
108 //
109 emit.ldarg_0.end();
110
111 if (!TypeHelper.IsSameOrParent(p.ParameterType, Context.Type))
112 emit.castclass(p.ParameterType);
113 }
114 else if (p.IsDefined(typeof (PropertyInfoAttribute), true))
115 {
116 // PropertyInfo.
117 //
118 emit.ldsfld(GetPropertyInfoField()).end();
119 }
120 else
121 throw new TypeBuilderException(string.Format(
122 Resources.TypeBuilder_UnknownParameterType,
123 mi.Name, mi.DeclaringType.FullName, p.Name));
124
125 }
126
127 if (InstanceType.IsValueType) emit.call (mi);
128 else emit.callvirt(mi);
129
130 memberType = mi.ReturnType;
131 }
132
133 if (propertyType.IsValueType)
134 {
135 if (memberType.IsValueType == false)
136 emit.CastFromObject(propertyType);
137 }
138 else
139 {
140 if (memberType != propertyType)
141 emit.castclass(propertyType);
142 }
143
144 emit.stloc(Context.ReturnValue);
145 }
146
147 protected override void BuildAbstractSetter()
148 {
149 var field = GetField();
150 var emit = Context.MethodBuilder.Emitter;
151 var propertyType = Context.CurrentProperty.PropertyType;
152 var setter = GetSetter();
153
154 if (InstanceType.IsValueType) emit.ldarg_0.ldflda(field);
155 else emit.ldarg_0.ldfld (field);
156
157 if (setter is PropertyInfo)
158 {
159 var pi = ((PropertyInfo)setter);
160
161 emit.ldarg_1.end();
162
163 if (propertyType.IsValueType && !pi.PropertyType.IsValueType)
164 emit.box(propertyType);
165
166 if (InstanceType.IsValueType) emit.call (pi.GetSetMethod());
167 else emit.callvirt(pi.GetSetMethod());
168 }
169 else if (setter is FieldInfo)
170 {
171 var fi = (FieldInfo)setter;
172
173 emit.ldarg_1.end();
174
175 if (propertyType.IsValueType && !fi.FieldType.IsValueType)
176 emit.box(propertyType);
177
178 emit.stfld(fi);
179 }
180 else
181 {
182 var mi = (MethodInfo)setter;
183 var pi = mi.GetParameters();
184 var gotValueParam = false;
185
186 for (var k = 0; k < pi.Length; k++)
187 {
188 var p = pi[k];
189
190 if (p.IsDefined(typeof (ParentAttribute), true))
191 {
192 // Parent - set this.
193 //
194 emit.ldarg_0.end();
195
196 if (!TypeHelper.IsSameOrParent(p.ParameterType, Context.Type))
197 emit.castclass(p.ParameterType);
198 }
199 else if (p.IsDefined(typeof (PropertyInfoAttribute), true))
200 {
201 // PropertyInfo.
202 //
203 emit.ldsfld(GetPropertyInfoField()).end();
204 }
205 else if (!gotValueParam)
206 {
207 // This must be a value.
208 //
209 emit.ldarg_1.end();
210
211 if (propertyType.IsValueType && !p.ParameterType.IsValueType)
212 emit.box(propertyType);
213
214 gotValueParam = true;
215 }
216 else
217 throw new TypeBuilderException(string.Format(
218 Resources.TypeBuilder_UnknownParameterType,
219 mi.Name, mi.DeclaringType.FullName, p.Name));
220 }
221
222 if (InstanceType.IsValueType) emit.call(mi);
223 else emit.callvirt(mi);
224 }
225 }
226
227 private MemberInfo GetGetter()
228 {
229 const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance;
230
231 var propertyType = Context.CurrentProperty.PropertyType;
232 var fields = InstanceType.GetFields(bindingFlags);
233
234 foreach (var field in fields)
235 {
236 var attrs = field.GetCustomAttributes(typeof(GetValueAttribute), true);
237
238 if (attrs.Length > 0 && TypeHelper.IsSameOrParent(field.FieldType, propertyType))
239 return field;
240 }
241
242 var props = InstanceType.GetProperties(bindingFlags);
243
244 foreach (var prop in props)
245 {
246 var attrs = prop.GetCustomAttributes(typeof(GetValueAttribute), true);
247
248 if (attrs.Length > 0 && TypeHelper.IsSameOrParent(prop.PropertyType, propertyType))
249 return prop;
250 }
251
252 foreach (var field in fields)
253 if (field.Name == "Value" && TypeHelper.IsSameOrParent(field.FieldType, propertyType))
254 return field;
255
256 foreach (var prop in props)
257 if (prop.Name == "Value" && TypeHelper.IsSameOrParent(prop.PropertyType, propertyType))
258 return prop;
259
260 var method = TypeHelper.GetMethod(InstanceType, false, "GetValue", bindingFlags);
261
262 if (method != null && TypeHelper.IsSameOrParent(propertyType, method.ReturnType))
263 return method;
264
265 throw new TypeBuilderException(string.Format(
266 Resources.TypeBuilder_CannotGetGetter, InstanceType.FullName,
267 propertyType.FullName, Context.CurrentProperty.Name, Context.Type.FullName));
268 }
269
270 private MemberInfo GetSetter()
271 {
272 const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance;
273
274 var propertyType = Context.CurrentProperty.PropertyType;
275 var fields = InstanceType.GetFields(bindingFlags);
276
277 foreach (var field in fields)
278 {
279 var attrs = field.GetCustomAttributes(typeof(SetValueAttribute), true);
280
281 if (attrs.Length > 0 && TypeHelper.IsSameOrParent(field.FieldType, propertyType))
282 return field;
283 }
284
285 var props = InstanceType.GetProperties(bindingFlags);
286
287 foreach (var prop in props)
288 {
289 var attrs = prop.GetCustomAttributes(typeof(SetValueAttribute), true);
290
291 if (attrs.Length > 0 && TypeHelper.IsSameOrParent(prop.PropertyType, propertyType))
292 return prop;
293 }
294
295 foreach (var field in fields)
296 if (field.Name == "Value" && TypeHelper.IsSameOrParent(field.FieldType, propertyType))
297 return field;
298
299 foreach (var prop in props)
300 if (prop.Name == "Value" && TypeHelper.IsSameOrParent(prop.PropertyType, propertyType))
301 return prop;
302
303 var method = TypeHelper.GetMethod(InstanceType, false, "SetValue", bindingFlags);
304
305 if (method != null && method.ReturnType == typeof(void))
306 return method;
307
308 throw new TypeBuilderException(string.Format(
309 Resources.TypeBuilder_CannotGetSetter, InstanceType.FullName,
310 propertyType.FullName, Context.CurrentProperty.Name, Context.Type.FullName));
311 }
312 }
313 }