Mercurial > pub > bltoolkit
comparison Source/TypeBuilder/Builders/ImplementInterfaceBuilder.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.Emit; | |
3 | |
4 namespace BLToolkit.TypeBuilder.Builders | |
5 { | |
6 using Reflection; | |
7 | |
8 class ImplementInterfaceBuilder : AbstractTypeBuilderBase | |
9 { | |
10 public ImplementInterfaceBuilder(Type type) | |
11 { | |
12 _type = type; | |
13 } | |
14 | |
15 private readonly Type _type; | |
16 | |
17 public override Type[] GetInterfaces() | |
18 { | |
19 return new[] { _type }; | |
20 } | |
21 | |
22 public override bool IsApplied(BuildContext context, AbstractTypeBuilderList builders) | |
23 { | |
24 if (context == null) throw new ArgumentNullException("context"); | |
25 | |
26 return context.BuildElement == BuildElement.InterfaceMethod; | |
27 } | |
28 | |
29 protected override void BuildInterfaceMethod() | |
30 { | |
31 var returnIfNonZero = false; | |
32 var returnIfZero = false; | |
33 | |
34 if (Context.ReturnValue != null) | |
35 { | |
36 var attrs = Context.MethodBuilder.OverriddenMethod.ReturnTypeCustomAttributes.GetCustomAttributes(true); | |
37 | |
38 foreach (var o in attrs) | |
39 { | |
40 if (o is ReturnIfNonZeroAttribute) returnIfNonZero = true; | |
41 else if (o is ReturnIfZeroAttribute) returnIfZero = true; | |
42 } | |
43 } | |
44 | |
45 var interfaceType = Context.CurrentInterface; | |
46 var emit = Context.MethodBuilder.Emitter; | |
47 | |
48 foreach (var de in Context.Fields) | |
49 { | |
50 var property = de.Key; | |
51 var field = de.Value; | |
52 | |
53 if (field.FieldType.IsPrimitive || field.FieldType == typeof(string)) | |
54 continue; | |
55 | |
56 var types = field.FieldType.GetInterfaces(); | |
57 | |
58 foreach (var type in types) | |
59 { | |
60 if (type != interfaceType.Type) | |
61 continue; | |
62 | |
63 var im = field.FieldType.GetInterfaceMap(type); | |
64 | |
65 for (var j = 0; j < im.InterfaceMethods.Length; j++) | |
66 { | |
67 if (im.InterfaceMethods[j] == Context.MethodBuilder.OverriddenMethod) | |
68 { | |
69 var targetMethod = im.TargetMethods[j]; | |
70 | |
71 var label = new Label(); | |
72 var checkNull = false; | |
73 | |
74 if (CallLazyInstanceInsurer(field) == false && field.FieldType.IsClass) | |
75 { | |
76 // Check if field is null. | |
77 // | |
78 checkNull = true; | |
79 | |
80 label = emit.DefineLabel(); | |
81 | |
82 emit | |
83 .ldarg_0 | |
84 .ldfld (field) | |
85 .brfalse_s (label) | |
86 ; | |
87 } | |
88 | |
89 // this. | |
90 // | |
91 emit | |
92 .ldarg_0 | |
93 .end(); | |
94 | |
95 // Load the field and prepare it for interface method call if the method is private. | |
96 // | |
97 if (field.FieldType.IsValueType) | |
98 { | |
99 if (targetMethod.IsPublic) | |
100 emit.ldflda (field); | |
101 else | |
102 emit | |
103 .ldfld (field) | |
104 .box (field.FieldType); | |
105 } | |
106 else | |
107 { | |
108 if (targetMethod.IsPublic) | |
109 emit.ldfld (field); | |
110 else | |
111 emit | |
112 .ldfld (field) | |
113 .castclass (interfaceType); | |
114 } | |
115 | |
116 // Check parameter attributes. | |
117 // | |
118 var pi = Context.MethodBuilder.OverriddenMethod.GetParameters(); | |
119 | |
120 for (var k = 0; k < pi.Length; k++) | |
121 { | |
122 var attrs = pi[k].GetCustomAttributes(true); | |
123 var stop = false; | |
124 | |
125 foreach (var a in attrs) | |
126 { | |
127 // Parent - set this. | |
128 // | |
129 if (a is ParentAttribute) | |
130 { | |
131 emit | |
132 .ldarg_0 | |
133 .end() | |
134 ; | |
135 | |
136 if (!TypeHelper.IsSameOrParent(pi[k].ParameterType, Context.Type)) | |
137 emit | |
138 .castclass (pi[k].ParameterType) | |
139 ; | |
140 | |
141 stop = true; | |
142 | |
143 break; | |
144 } | |
145 | |
146 // PropertyInfo. | |
147 // | |
148 if (a is PropertyInfoAttribute) | |
149 { | |
150 var ifb = GetPropertyInfoField(property); | |
151 | |
152 emit.ldsfld(ifb); | |
153 stop = true; | |
154 | |
155 break; | |
156 } | |
157 } | |
158 | |
159 if (stop) | |
160 continue; | |
161 | |
162 // Pass argument. | |
163 // | |
164 emit.ldarg ((byte)(k + 1)); | |
165 } | |
166 | |
167 // Call the method. | |
168 // | |
169 if (field.FieldType.IsValueType) | |
170 { | |
171 if (targetMethod.IsPublic) emit.call (targetMethod); | |
172 else emit.callvirt (im.InterfaceMethods[j]); | |
173 } | |
174 else | |
175 { | |
176 if (targetMethod.IsPublic) emit.callvirt (targetMethod); | |
177 else emit.callvirt (im.InterfaceMethods[j]); | |
178 } | |
179 | |
180 // Return if appropriated result. | |
181 // | |
182 if (Context.ReturnValue != null) | |
183 { | |
184 emit.stloc(Context.ReturnValue); | |
185 | |
186 if (returnIfNonZero) | |
187 { | |
188 emit | |
189 .ldloc (Context.ReturnValue) | |
190 .brtrue (Context.ReturnLabel); | |
191 } | |
192 else if (returnIfZero) | |
193 { | |
194 emit | |
195 .ldloc (Context.ReturnValue) | |
196 .brfalse (Context.ReturnLabel); | |
197 } | |
198 } | |
199 | |
200 if (checkNull) | |
201 emit.MarkLabel(label); | |
202 | |
203 break; | |
204 } | |
205 } | |
206 | |
207 break; | |
208 } | |
209 } | |
210 } | |
211 } | |
212 } |