Mercurial > pub > bltoolkit
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 } |