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 }