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