0
|
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 }
|