comparison Source/TypeBuilder/Builders/DefaultTypeBuilder.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.Collections;
3 using System.Reflection;
4 using System.Reflection.Emit;
5 using System.Collections.Generic;
6
7 namespace BLToolkit.TypeBuilder.Builders
8 {
9 using Properties;
10 using Reflection;
11 using Reflection.Emit;
12
13 public class DefaultTypeBuilder : AbstractTypeBuilderBase
14 {
15 #region Interface Overrides
16
17 public override bool IsCompatible(BuildContext context, IAbstractTypeBuilder typeBuilder)
18 {
19 return IsRelative(typeBuilder) == false;
20 }
21
22 public override bool IsApplied(BuildContext context, AbstractTypeBuilderList builders)
23 {
24 if (context == null) throw new ArgumentNullException("context");
25
26 if (context.IsAbstractProperty && context.IsBeforeOrBuildStep)
27 {
28 return context.CurrentProperty.GetIndexParameters().Length <= 1;
29 }
30
31 return context.BuildElement == BuildElement.Type && context.IsAfterStep;
32 }
33
34 #endregion
35
36 #region Get/Set Implementation
37
38 protected override void BuildAbstractGetter()
39 {
40 var field = GetField();
41 var index = Context.CurrentProperty.GetIndexParameters();
42
43 switch (index.Length)
44 {
45 case 0:
46 Context.MethodBuilder.Emitter
47 .ldarg_0
48 .ldfld (field)
49 .stloc (Context.ReturnValue)
50 ;
51 break;
52
53 case 1:
54 Context.MethodBuilder.Emitter
55 .ldarg_0
56 .ldfld (field)
57 .ldarg_1
58 .boxIfValueType (index[0].ParameterType)
59 .callvirt (typeof(Dictionary<object,object>), "get_Item", typeof(object))
60 .castType (Context.CurrentProperty.PropertyType)
61 .stloc (Context.ReturnValue)
62 ;
63 break;
64 }
65 }
66
67 protected override void BuildAbstractSetter()
68 {
69 var field = GetField();
70 var index = Context.CurrentProperty.GetIndexParameters();
71
72 switch (index.Length)
73 {
74 case 0:
75 Context.MethodBuilder.Emitter
76 .ldarg_0
77 .ldarg_1
78 .stfld (field)
79 ;
80 //Context.MethodBuilder.Emitter.AddMaxStackSize(6);
81 break;
82
83 case 1:
84 Context.MethodBuilder.Emitter
85 .ldarg_0
86 .ldfld (field)
87 .ldarg_1
88 .boxIfValueType (index[0].ParameterType)
89 .ldarg_2
90 .boxIfValueType (Context.CurrentProperty.PropertyType)
91 .callvirt (typeof(Dictionary<object,object>), "set_Item", typeof(object), typeof(object))
92 ;
93 break;
94 }
95 }
96
97 #endregion
98
99 #region Call Base Method
100
101 protected override void BuildVirtualGetter()
102 {
103 CallBaseMethod();
104 }
105
106 protected override void BuildVirtualSetter()
107 {
108 CallBaseMethod();
109 }
110
111 protected override void BuildVirtualMethod()
112 {
113 CallBaseMethod();
114 }
115
116 private void CallBaseMethod()
117 {
118 var emit = Context.MethodBuilder.Emitter;
119 var method = Context.MethodBuilder.OverriddenMethod;
120 var ps = method.GetParameters();
121
122 emit.ldarg_0.end();
123
124 for (var i = 0; i < ps.Length; i++)
125 emit.ldarg(i + 1);
126
127 emit.call(method);
128
129 if (Context.ReturnValue != null)
130 emit.stloc(Context.ReturnValue);
131 }
132
133 #endregion
134
135 #region Properties
136
137 private static TypeHelper _initContextType;
138 protected static TypeHelper InitContextType
139 {
140 get { return _initContextType ?? (_initContextType = new TypeHelper(typeof(InitContext))); }
141 }
142
143 #endregion
144
145 #region Field Initialization
146
147 #region Overrides
148
149 protected override void BeforeBuildAbstractGetter()
150 {
151 CallLazyInstanceInsurer(GetField());
152 }
153
154 protected override void BeforeBuildAbstractSetter()
155 {
156 var field = GetField();
157
158 if (field.FieldType != Context.CurrentProperty.PropertyType)
159 CallLazyInstanceInsurer(field);
160 }
161
162 #endregion
163
164 #region Common
165
166 protected FieldBuilder GetField()
167 {
168 var propertyInfo = Context.CurrentProperty;
169 var fieldName = GetFieldName();
170 var fieldType = GetFieldType();
171 var field = Context.GetField(fieldName);
172
173 if (field == null)
174 {
175 field = Context.CreatePrivateField(propertyInfo, fieldName, fieldType);
176
177 if (TypeAccessor.IsInstanceBuildable(fieldType))
178 {
179 var noInstance = propertyInfo.GetCustomAttributes(typeof(NoInstanceAttribute), true).Length > 0;
180
181 if (IsObjectHolder && noInstance)
182 {
183 BuildHolderInstance(Context.TypeBuilder.DefaultConstructor.Emitter);
184 BuildHolderInstance(Context.TypeBuilder.InitConstructor.Emitter);
185 }
186 else if (!noInstance)
187 {
188 if (fieldType.IsClass && IsLazyInstance(fieldType))
189 {
190 BuildLazyInstanceEnsurer();
191 }
192 else
193 {
194 BuildDefaultInstance();
195 BuildInitContextInstance();
196 }
197 }
198 }
199 }
200
201 return field;
202 }
203
204 #endregion
205
206 #region Build
207
208 private void BuildHolderInstance(EmitHelper emit)
209 {
210 var fieldName = GetFieldName();
211 var field = Context.GetField(fieldName);
212 var fieldType = new TypeHelper(field.FieldType);
213 var objectType = new TypeHelper(GetObjectType());
214
215 var ci = fieldType.GetPublicDefaultConstructor();
216
217 if (ci != null)
218 {
219 emit
220 .ldarg_0
221 .newobj (ci)
222 .stfld (field)
223 ;
224 }
225 else
226 {
227 if (!CheckObjectHolderCtor(fieldType, objectType))
228 return;
229
230 emit
231 .ldarg_0
232 .ldnull
233 .newobj (fieldType, objectType)
234 .stfld (field)
235 ;
236 }
237 }
238
239 private void CreateDefaultInstance(
240 FieldBuilder field, TypeHelper fieldType, TypeHelper objectType, EmitHelper emit)
241 {
242 if (!CheckObjectHolderCtor(fieldType, objectType))
243 return;
244
245 if (objectType.Type == typeof(string))
246 {
247 emit
248 .ldarg_0
249 .LoadInitValue (objectType)
250 ;
251 }
252 else if (objectType.IsArray)
253 {
254 var initializer = GetArrayInitializer(objectType);
255
256 emit
257 .ldarg_0
258 .ldsfld (initializer)
259 ;
260 }
261 else
262 {
263 var ci = objectType.GetPublicDefaultConstructor();
264
265 if (ci == null)
266 {
267 if (objectType.Type.IsValueType)
268 return;
269
270 var message = string.Format(
271 Resources.TypeBuilder_PropertyTypeHasNoPublicDefaultCtor,
272 Context.CurrentProperty.Name,
273 Context.Type.FullName,
274 objectType.FullName);
275
276 emit
277 .ldstr (message)
278 .newobj (typeof(TypeBuilderException), typeof(string))
279 .@throw
280 .end()
281 ;
282
283 return;
284 }
285
286 emit
287 .ldarg_0
288 .newobj (ci)
289 ;
290 }
291
292 if (IsObjectHolder)
293 {
294 emit
295 .newobj (fieldType, objectType)
296 ;
297 }
298
299 emit
300 .stfld (field)
301 ;
302 }
303
304 private void CreateParametrizedInstance(
305 FieldBuilder field, TypeHelper fieldType, TypeHelper objectType, EmitHelper emit, object[] parameters)
306 {
307 if (!CheckObjectHolderCtor(fieldType, objectType))
308 return;
309
310 Stack<ConstructorInfo> genericNestedConstructors;
311 if (parameters.Length == 1)
312 {
313 var o = parameters[0];
314
315 if (o == null)
316 {
317 if (objectType.IsValueType == false)
318 emit
319 .ldarg_0
320 .ldnull
321 .end()
322 ;
323
324 if (IsObjectHolder)
325 {
326 emit
327 .newobj (fieldType, objectType)
328 ;
329 }
330 else
331 {
332 if (objectType.Type.IsGenericType)
333 {
334 Type nullableType = null;
335 genericNestedConstructors = GetGenericNestedConstructors(
336 objectType,
337 typeHelper =>
338 typeHelper.IsValueType == false ||
339 (typeHelper.Type.IsGenericType && typeHelper.Type.GetGenericTypeDefinition() == typeof (Nullable<>)),
340 typeHelper => { nullableType = typeHelper.Type; },
341 () => nullableType != null);
342
343 if (nullableType == null)
344 throw new Exception("Cannot find nullable type in generic types chain");
345
346 if (nullableType.IsValueType == false)
347 {
348 emit
349 .ldarg_0
350 .ldnull
351 .end()
352 ;
353 }
354 else
355 {
356 var nullable = emit.DeclareLocal(nullableType);
357
358 emit
359 .ldloca(nullable)
360 .initobj(nullableType)
361 .ldarg_0
362 .ldloc(nullable)
363 ;
364
365 if (genericNestedConstructors != null)
366 {
367 while (genericNestedConstructors.Count != 0)
368 {
369 emit
370 .newobj(genericNestedConstructors.Pop())
371 ;
372 }
373 }
374 }
375 }
376 }
377
378 emit
379 .stfld (field)
380 ;
381
382 return;
383 }
384
385 if (objectType.Type == o.GetType())
386 {
387 if (objectType.Type == typeof(string))
388 {
389 emit
390 .ldarg_0
391 .ldstr ((string)o)
392 .stfld (field)
393 ;
394
395 return;
396 }
397
398 if (objectType.IsValueType)
399 {
400 emit.ldarg_0.end();
401
402 if (emit.LoadWellKnownValue(o) == false)
403 {
404 emit
405 .ldsfld (GetParameterField())
406 .ldc_i4_0
407 .ldelem_ref
408 .end()
409 ;
410 }
411
412 emit.stfld(field);
413
414 return;
415 }
416 }
417 }
418
419 var types = new Type[parameters.Length];
420
421 for (var i = 0; i < parameters.Length; i++)
422 {
423 if (parameters[i] != null)
424 {
425 var t = parameters[i].GetType();
426
427 types[i] = (t.IsEnum) ? Enum.GetUnderlyingType(t) : t;
428 }
429 else
430 types[i] = typeof(object);
431 }
432
433 // Do some heuristics for Nullable<DateTime> and EditableValue<Decimal>
434 //
435 ConstructorInfo objectCtor = null;
436 genericNestedConstructors = GetGenericNestedConstructors(
437 objectType,
438 typeHelper => true,
439 typeHelper => { objectCtor = typeHelper.GetPublicConstructor(types); },
440 () => objectCtor != null);
441
442 if (objectCtor == null)
443 {
444 if (objectType.IsValueType)
445 return;
446
447 throw new TypeBuilderException(
448 string.Format(types.Length == 0?
449 Resources.TypeBuilder_PropertyTypeHasNoPublicDefaultCtor:
450 Resources.TypeBuilder_PropertyTypeHasNoPublicCtor,
451 Context.CurrentProperty.Name,
452 Context.Type.FullName,
453 objectType.FullName));
454 }
455
456 var pi = objectCtor.GetParameters();
457
458 emit.ldarg_0.end();
459
460 for (var i = 0; i < parameters.Length; i++)
461 {
462 var o = parameters[i];
463 var oType = o.GetType();
464
465 if (emit.LoadWellKnownValue(o))
466 {
467 if (oType.IsValueType)
468 {
469 if (!pi[i].ParameterType.IsValueType)
470 emit.box(oType);
471 else if (Type.GetTypeCode(oType) != Type.GetTypeCode(pi[i].ParameterType))
472 emit.conv(pi[i].ParameterType);
473 }
474 }
475 else
476 {
477 emit
478 .ldsfld (GetParameterField())
479 .ldc_i4 (i)
480 .ldelem_ref
481 .CastFromObject (types[i])
482 ;
483
484 if (oType.IsValueType && !pi[i].ParameterType.IsValueType)
485 emit.box(oType);
486 }
487 }
488
489 emit
490 .newobj (objectCtor)
491 ;
492
493 if (genericNestedConstructors != null)
494 {
495 while (genericNestedConstructors.Count != 0)
496 {
497 emit
498 .newobj(genericNestedConstructors.Pop())
499 ;
500 }
501 }
502
503 if (IsObjectHolder)
504 {
505 emit
506 .newobj (fieldType, objectType)
507 ;
508 }
509
510 emit
511 .stfld (field)
512 ;
513 }
514
515 private Stack<ConstructorInfo> GetGenericNestedConstructors(TypeHelper objectType,
516 Predicate<TypeHelper> isActionable,
517 Action<TypeHelper> action,
518 Func<bool> isBreakCondition)
519 {
520 Stack<ConstructorInfo> genericNestedConstructors = null;
521
522 if (isActionable(objectType))
523 action(objectType);
524
525 while (objectType.Type.IsGenericType && !isBreakCondition())
526 {
527 var typeArgs = objectType.Type.GetGenericArguments();
528
529 if (typeArgs.Length == 1)
530 {
531 var genericCtor = objectType.GetPublicConstructor(typeArgs[0]);
532
533 if (genericCtor != null)
534 {
535 if (genericNestedConstructors == null)
536 genericNestedConstructors = new Stack<ConstructorInfo>();
537
538 genericNestedConstructors.Push(genericCtor);
539 objectType = typeArgs[0];
540
541 if (isActionable(objectType))
542 action(objectType);
543 }
544 }
545 else
546 {
547 throw new TypeBuilderException(
548 string.Format(Resources.TypeBuilder_GenericShouldBeSingleTyped,
549 Context.CurrentProperty.Name,
550 Context.Type.FullName,
551 objectType.FullName));
552 }
553 }
554
555 return genericNestedConstructors;
556 }
557
558 #endregion
559
560 #region Build InitContext Instance
561
562 private void BuildInitContextInstance()
563 {
564 var fieldName = GetFieldName();
565 var field = Context.GetField(fieldName);
566 var fieldType = new TypeHelper(field.FieldType);
567 var objectType = new TypeHelper(GetObjectType());
568
569 var emit = Context.TypeBuilder.InitConstructor.Emitter;
570
571 var parameters = TypeHelper.GetPropertyParameters(Context.CurrentProperty);
572 var ci = objectType.GetPublicConstructor(typeof(InitContext));
573
574 if (ci != null && ci.GetParameters()[0].ParameterType != typeof(InitContext))
575 ci = null;
576
577 if (ci != null || objectType.IsAbstract)
578 CreateAbstractInitContextInstance(field, fieldType, objectType, emit, parameters);
579 else if (parameters == null)
580 CreateDefaultInstance(field, fieldType, objectType, emit);
581 else
582 CreateParametrizedInstance(field, fieldType, objectType, emit, parameters);
583 }
584
585 private void CreateAbstractInitContextInstance(
586 FieldBuilder field, TypeHelper fieldType, TypeHelper objectType, EmitHelper emit, object[] parameters)
587 {
588 if (!CheckObjectHolderCtor(fieldType, objectType))
589 return;
590
591 var memberParams = InitContextType.GetProperty("MemberParameters").GetSetMethod();
592 var parentField = Context.GetItem<LocalBuilder>("$BLToolkit.InitContext.Parent");
593
594 if (parentField == null)
595 {
596 Context.Items.Add("$BLToolkit.InitContext.Parent", parentField = emit.DeclareLocal(typeof(object)));
597
598 var label = emit.DefineLabel();
599
600 emit
601 .ldarg_1
602 .brtrue_s (label)
603
604 .newobj (InitContextType.GetPublicDefaultConstructor())
605 .starg (1)
606
607 .ldarg_1
608 .ldc_i4_1
609 .callvirt (InitContextType.GetProperty("IsInternal").GetSetMethod())
610
611 .MarkLabel (label)
612
613 .ldarg_1
614 .callvirt (InitContextType.GetProperty("Parent").GetGetMethod())
615 .stloc (parentField)
616 ;
617 }
618
619 emit
620 .ldarg_1
621 .ldarg_0
622 .callvirt (InitContextType.GetProperty("Parent").GetSetMethod())
623 ;
624
625 var isDirty = Context.GetItem<bool?>("$BLToolkit.InitContext.DirtyParameters");
626
627 if (parameters != null)
628 {
629 emit
630 .ldarg_1
631 .ldsfld (GetParameterField())
632 .callvirt (memberParams)
633 ;
634 }
635 else if (isDirty != null && (bool)isDirty)
636 {
637 emit
638 .ldarg_1
639 .ldnull
640 .callvirt (memberParams)
641 ;
642 }
643
644 if (Context.Items.ContainsKey("$BLToolkit.InitContext.DirtyParameters"))
645 Context.Items["$BLToolkit.InitContext.DirtyParameters"] = (bool?)(parameters != null);
646 else
647 Context.Items.Add("$BLToolkit.InitContext.DirtyParameters", (bool?)(parameters != null));
648
649 if (objectType.IsAbstract)
650 {
651 emit
652 .ldarg_0
653 .ldsfld (GetTypeAccessorField())
654 .ldarg_1
655 .callvirtNoGenerics (typeof(TypeAccessor), "CreateInstanceEx", _initContextType)
656 .isinst (objectType)
657 ;
658 }
659 else
660 {
661 emit
662 .ldarg_0
663 .ldarg_1
664 .newobj (objectType.GetPublicConstructor(typeof(InitContext)))
665 ;
666 }
667
668 if (IsObjectHolder)
669 {
670 emit
671 .newobj (fieldType, objectType)
672 ;
673 }
674
675 emit
676 .stfld (field)
677 ;
678 }
679
680 #endregion
681
682 #region Build Default Instance
683
684 private void BuildDefaultInstance()
685 {
686 var fieldName = GetFieldName();
687 var field = Context.GetField(fieldName);
688 var fieldType = new TypeHelper(field.FieldType);
689 var objectType = new TypeHelper(GetObjectType());
690
691 var emit = Context.TypeBuilder.DefaultConstructor.Emitter;
692 var ps = TypeHelper.GetPropertyParameters(Context.CurrentProperty);
693 var ci = objectType.GetPublicConstructor(typeof(InitContext));
694
695 if (ci != null && ci.GetParameters()[0].ParameterType != typeof(InitContext))
696 ci = null;
697
698 if (ci != null || objectType.IsAbstract)
699 CreateInitContextDefaultInstance(
700 "$BLToolkit.DefaultInitContext.", field, fieldType, objectType, emit, ps);
701 else if (ps == null)
702 CreateDefaultInstance(field, fieldType, objectType, emit);
703 else
704 CreateParametrizedInstance(field, fieldType, objectType, emit, ps);
705 }
706
707 private bool CheckObjectHolderCtor(TypeHelper fieldType, TypeHelper objectType)
708 {
709 if (IsObjectHolder)
710 {
711 var holderCi = fieldType.GetPublicConstructor(objectType);
712
713 if (holderCi == null)
714 {
715 var message = string.Format(
716 Resources.TypeBuilder_PropertyTypeHasNoCtorWithParamType,
717 Context.CurrentProperty.Name,
718 Context.Type.FullName,
719 fieldType.FullName,
720 objectType.FullName);
721
722 Context.TypeBuilder.DefaultConstructor.Emitter
723 .ldstr (message)
724 .newobj (typeof(TypeBuilderException), typeof(string))
725 .@throw
726 .end()
727 ;
728
729 return false;
730 }
731 }
732
733 return true;
734 }
735
736 private void CreateInitContextDefaultInstance(
737 string initContextName,
738 FieldBuilder field,
739 TypeHelper fieldType,
740 TypeHelper objectType,
741 EmitHelper emit,
742 object[] parameters)
743 {
744 if (!CheckObjectHolderCtor(fieldType, objectType))
745 return;
746
747 var initField = GetInitContextBuilder(initContextName, emit);
748 var memberParams = InitContextType.GetProperty("MemberParameters").GetSetMethod();
749
750 if (parameters != null)
751 {
752 emit
753 .ldloc (initField)
754 .ldsfld (GetParameterField())
755 .callvirt (memberParams)
756 ;
757 }
758 else if ((bool)Context.Items["$BLToolkit.Default.DirtyParameters"])
759 {
760 emit
761 .ldloc (initField)
762 .ldnull
763 .callvirt (memberParams)
764 ;
765 }
766
767 Context.Items["$BLToolkit.Default.DirtyParameters"] = parameters != null;
768
769 if (objectType.IsAbstract)
770 {
771 emit
772 .ldarg_0
773 .ldsfld (GetTypeAccessorField())
774 .ldloc (initField)
775 .callvirtNoGenerics (typeof(TypeAccessor), "CreateInstanceEx", _initContextType)
776 .isinst (objectType)
777 ;
778 }
779 else
780 {
781 emit
782 .ldarg_0
783 .ldloc (initField)
784 .newobj (objectType.GetPublicConstructor(typeof(InitContext)))
785 ;
786 }
787
788 if (IsObjectHolder)
789 {
790 emit
791 .newobj (fieldType, objectType)
792 ;
793 }
794
795 emit
796 .stfld (field)
797 ;
798 }
799
800 private LocalBuilder GetInitContextBuilder(
801 string initContextName, EmitHelper emit)
802 {
803 var initField = Context.GetItem<LocalBuilder>(initContextName);
804
805 if (initField == null)
806 {
807 Context.Items.Add(initContextName, initField = emit.DeclareLocal(InitContextType));
808
809 emit
810 .newobj (InitContextType.GetPublicDefaultConstructor())
811
812 .dup
813 .ldarg_0
814 .callvirt (InitContextType.GetProperty("Parent").GetSetMethod())
815
816 .dup
817 .ldc_i4_1
818 .callvirt (InitContextType.GetProperty("IsInternal").GetSetMethod())
819
820 .stloc (initField)
821 ;
822
823 Context.Items.Add("$BLToolkit.Default.DirtyParameters", false);
824 }
825
826 return initField;
827 }
828
829 #endregion
830
831 #region Build Lazy Instance
832
833 private bool IsLazyInstance(Type type)
834 {
835 var attrs = Context.CurrentProperty.GetCustomAttributes(typeof(LazyInstanceAttribute), true);
836
837 if (attrs.Length > 0)
838 return ((LazyInstanceAttribute)attrs[0]).IsLazy;
839
840 attrs = Context.Type.GetAttributes(typeof(LazyInstancesAttribute));
841
842 foreach (LazyInstancesAttribute a in attrs)
843 if (a.Type == typeof(object) || type == a.Type || type.IsSubclassOf(a.Type))
844 return a.IsLazy;
845
846 return false;
847 }
848
849 private void BuildLazyInstanceEnsurer()
850 {
851 var fieldName = GetFieldName();
852 var field = Context.GetField(fieldName);
853 var fieldType = new TypeHelper(field.FieldType);
854 var objectType = new TypeHelper(GetObjectType());
855 var ensurer = Context.TypeBuilder.DefineMethod(
856 string.Format("$EnsureInstance{0}", fieldName),
857 MethodAttributes.Private | MethodAttributes.HideBySig);
858
859 var emit = ensurer.Emitter;
860 var end = emit.DefineLabel();
861
862 emit
863 .ldarg_0
864 .ldfld (field)
865 .brtrue_s (end)
866 ;
867
868 var parameters = TypeHelper.GetPropertyParameters(Context.CurrentProperty);
869 var ci = objectType.GetPublicConstructor(typeof(InitContext));
870
871 if (ci != null || objectType.IsAbstract)
872 CreateInitContextLazyInstance(field, fieldType, objectType, emit, parameters);
873 else if (parameters == null)
874 CreateDefaultInstance(field, fieldType, objectType, emit);
875 else
876 CreateParametrizedInstance(field, fieldType, objectType, emit, parameters);
877
878 emit
879 .MarkLabel(end)
880 .ret()
881 ;
882
883 Context.Items.Add("$BLToolkit.FieldInstanceEnsurer." + fieldName, ensurer);
884 }
885
886 private void CreateInitContextLazyInstance(
887 FieldBuilder field,
888 TypeHelper fieldType,
889 TypeHelper objectType,
890 EmitHelper emit,
891 object[] parameters)
892 {
893 if (!CheckObjectHolderCtor(fieldType, objectType))
894 return;
895
896 var initField = emit.DeclareLocal(InitContextType);
897
898 emit
899 .newobj (InitContextType.GetPublicDefaultConstructor())
900
901 .dup
902 .ldarg_0
903 .callvirt (InitContextType.GetProperty("Parent").GetSetMethod())
904
905 .dup
906 .ldc_i4_1
907 .callvirt (InitContextType.GetProperty("IsInternal").GetSetMethod())
908
909 .dup
910 .ldc_i4_1
911 .callvirt (InitContextType.GetProperty("IsLazyInstance").GetSetMethod())
912
913 ;
914
915 if (parameters != null)
916 {
917 emit
918 .dup
919 .ldsfld (GetParameterField())
920 .callvirt (InitContextType.GetProperty("MemberParameters").GetSetMethod())
921 ;
922 }
923
924 emit
925 .stloc (initField);
926
927 if (objectType.IsAbstract)
928 {
929 emit
930 .ldarg_0
931 .ldsfld (GetTypeAccessorField())
932 .ldloc (initField)
933 .callvirtNoGenerics (typeof(TypeAccessor), "CreateInstanceEx", _initContextType)
934 .isinst (objectType)
935 ;
936 }
937 else
938 {
939 emit
940 .ldarg_0
941 .ldloc (initField)
942 .newobj (objectType.GetPublicConstructor(typeof(InitContext)))
943 ;
944 }
945
946 if (IsObjectHolder)
947 {
948 emit
949 .newobj (fieldType, objectType)
950 ;
951 }
952
953 emit
954 .stfld (field)
955 ;
956 }
957
958 #endregion
959
960 #region Finalize Type
961
962 protected override void AfterBuildType()
963 {
964 var isDirty = Context.GetItem<bool?>("$BLToolkit.InitContext.DirtyParameters");
965
966 if (isDirty != null && isDirty.Value)
967 {
968 Context.TypeBuilder.InitConstructor.Emitter
969 .ldarg_1
970 .ldnull
971 .callvirt (InitContextType.GetProperty("MemberParameters").GetSetMethod())
972 ;
973 }
974
975 var localBuilder = Context.GetItem<LocalBuilder>("$BLToolkit.InitContext.Parent");
976
977 if (localBuilder != null)
978 {
979 Context.TypeBuilder.InitConstructor.Emitter
980 .ldarg_1
981 .ldloc (localBuilder)
982 .callvirt (InitContextType.GetProperty("Parent").GetSetMethod())
983 ;
984 }
985
986 FinalizeDefaultConstructors();
987 FinalizeInitContextConstructors();
988 }
989
990 private void FinalizeDefaultConstructors()
991 {
992 var ci = Context.Type.GetDefaultConstructor();
993
994 if (ci == null || Context.TypeBuilder.IsDefaultConstructorDefined)
995 {
996 var emit = Context.TypeBuilder.DefaultConstructor.Emitter;
997
998 if (ci != null)
999 {
1000 emit.ldarg_0.call(ci);
1001 }
1002 else
1003 {
1004 ci = Context.Type.GetConstructor(typeof(InitContext));
1005
1006 if (ci != null)
1007 {
1008 var initField = GetInitContextBuilder("$BLToolkit.DefaultInitContext.", emit);
1009
1010 emit
1011 .ldarg_0
1012 .ldloc (initField)
1013 .call (ci);
1014 }
1015 else
1016 {
1017 if (Context.Type.GetConstructors().Length > 0)
1018 throw new TypeBuilderException(string.Format(
1019 Resources.TypeBuilder_NoDefaultCtor,
1020 Context.Type.FullName));
1021 }
1022 }
1023 }
1024 }
1025
1026 private void FinalizeInitContextConstructors()
1027 {
1028 var ci = Context.Type.GetConstructor(typeof(InitContext));
1029
1030 if (ci != null || Context.TypeBuilder.IsInitConstructorDefined)
1031 {
1032 var emit = Context.TypeBuilder.InitConstructor.Emitter;
1033
1034 if (ci != null)
1035 {
1036 emit
1037 .ldarg_0
1038 .ldarg_1
1039 .call (ci);
1040 }
1041 else
1042 {
1043 ci = Context.Type.GetDefaultConstructor();
1044
1045 if (ci != null)
1046 {
1047 emit.ldarg_0.call(ci);
1048 }
1049 else
1050 {
1051 if (Context.Type.GetConstructors().Length > 0)
1052 throw new TypeBuilderException(
1053 string.Format(Resources.TypeBuilder_NoDefaultCtor,
1054 Context.Type.FullName));
1055 }
1056 }
1057 }
1058 }
1059
1060 #endregion
1061
1062 #endregion
1063 }
1064 }