Mercurial > pub > bltoolkit
comparison Source/Aspects/Builders/MixinAspectBuilder.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; | |
3 using System.Reflection.Emit; | |
4 | |
5 using BLToolkit.TypeBuilder.Builders; | |
6 using BLToolkit.Reflection.Emit; | |
7 using BLToolkit.TypeBuilder; | |
8 | |
9 namespace BLToolkit.Aspects.Builders | |
10 { | |
11 public class MixinAspectBuilder : AbstractTypeBuilderBase | |
12 { | |
13 public MixinAspectBuilder( | |
14 Type targetInterface, string memberName, bool throwExceptionIfNull, string exceptionMessage) | |
15 { | |
16 _targetInterface = targetInterface; | |
17 _memberName = memberName; | |
18 _throwExceptionIfNull = throwExceptionIfNull; | |
19 _exceptionMessage = exceptionMessage; | |
20 } | |
21 | |
22 private readonly Type _targetInterface; | |
23 private readonly string _memberName; | |
24 private readonly bool _throwExceptionIfNull; | |
25 private readonly string _exceptionMessage; | |
26 | |
27 public override bool IsApplied(BuildContext context, AbstractTypeBuilderList builders) | |
28 { | |
29 return context.BuildElement == BuildElement.InterfaceMethod; | |
30 } | |
31 | |
32 public override Type[] GetInterfaces() | |
33 { | |
34 return new Type[] { _targetInterface }; | |
35 } | |
36 | |
37 public override void Build(BuildContext context) | |
38 { | |
39 Context = context; | |
40 | |
41 if (CheckOverrideAttribute()) | |
42 return; | |
43 | |
44 EmitHelper emit = Context.MethodBuilder.Emitter; | |
45 MethodInfo method = Context.MethodBuilder.OverriddenMethod; | |
46 ParameterInfo[] ps = method.GetParameters(); | |
47 Type memberType; | |
48 | |
49 FieldInfo field = Context.Type.GetField(_memberName); | |
50 | |
51 if (field != null) | |
52 { | |
53 if (field.IsPrivate) | |
54 throw new TypeBuilderException(string.Format( | |
55 "Field '{0}.{1}' must be protected or public.", | |
56 Context.Type.Name, _memberName)); | |
57 | |
58 memberType = field.FieldType; | |
59 | |
60 emit | |
61 .ldarg_0 | |
62 .ldfld (field) | |
63 ; | |
64 | |
65 CheckNull(emit); | |
66 | |
67 emit | |
68 .ldarg_0 | |
69 .ldfld (field) | |
70 ; | |
71 } | |
72 else | |
73 { | |
74 PropertyInfo prop = Context.Type.GetProperty(_memberName); | |
75 | |
76 if (prop != null) | |
77 { | |
78 MethodInfo mi = prop.GetGetMethod(true); | |
79 | |
80 if (mi == null) | |
81 throw new TypeBuilderException(string.Format( | |
82 "Property '{0}.{1}' getter not found.", | |
83 Context.Type.Name, _memberName)); | |
84 | |
85 memberType = prop.PropertyType; | |
86 | |
87 if (mi.IsPrivate) | |
88 throw new TypeBuilderException(string.Format( | |
89 "Property '{0}.{1}' getter must be protected or public.", | |
90 Context.Type.Name, _memberName)); | |
91 | |
92 emit | |
93 .ldarg_0 | |
94 .callvirt (mi) | |
95 ; | |
96 | |
97 CheckNull(emit); | |
98 | |
99 emit | |
100 .ldarg_0 | |
101 .callvirt (mi) | |
102 ; | |
103 } | |
104 else | |
105 { | |
106 throw new TypeBuilderException(string.Format( | |
107 "Member '{0}.{1}' not found.", | |
108 Context.Type.Name, _memberName)); | |
109 } | |
110 } | |
111 | |
112 emit.CastIfNecessary(_targetInterface, memberType); | |
113 | |
114 for (int i = 0; i < ps.Length; i++) | |
115 emit.ldarg(i + 1); | |
116 | |
117 emit.callvirt(method); | |
118 | |
119 if (Context.ReturnValue != null) | |
120 emit.stloc(Context.ReturnValue); | |
121 } | |
122 | |
123 private void CheckNull(EmitHelper emit) | |
124 { | |
125 if (_throwExceptionIfNull == false && string.IsNullOrEmpty(_exceptionMessage)) | |
126 { | |
127 emit | |
128 .brfalse (Context.ReturnLabel) | |
129 ; | |
130 } | |
131 else | |
132 { | |
133 string message = string.Format( | |
134 string.IsNullOrEmpty(_exceptionMessage)? | |
135 "'{0}.{1}' is not initialized." : _exceptionMessage, | |
136 _targetInterface.Name, _memberName, _targetInterface.FullName); | |
137 | |
138 Label label = emit.DefineLabel(); | |
139 | |
140 emit | |
141 .brtrue (label) | |
142 .ldstr (message) | |
143 .newobj (typeof(InvalidOperationException), typeof(string)) | |
144 .@throw | |
145 .MarkLabel (label) | |
146 ; | |
147 } | |
148 } | |
149 | |
150 private bool CheckOverrideAttribute() | |
151 { | |
152 MethodInfo method = Context.MethodBuilder.OverriddenMethod; | |
153 ParameterInfo[] ps = method.GetParameters(); | |
154 | |
155 MethodInfo[] methods = Context.Type.GetMethods( | |
156 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); | |
157 | |
158 foreach (MethodInfo mi in methods) | |
159 { | |
160 if (mi.IsPrivate) | |
161 continue; | |
162 | |
163 object[] attrs = mi.GetCustomAttributes(typeof(MixinOverrideAttribute), true); | |
164 | |
165 if (attrs == null || attrs.Length == 0) | |
166 continue; | |
167 | |
168 foreach (MixinOverrideAttribute attr in attrs) | |
169 { | |
170 if (attr.TargetInterface != null && | |
171 attr.TargetInterface != Context.CurrentInterface.Type) | |
172 continue; | |
173 | |
174 string name = string.IsNullOrEmpty(attr.MethodName)? | |
175 mi.Name: attr.MethodName; | |
176 | |
177 if (name != method.Name || mi.ReturnType != method.ReturnType) | |
178 continue; | |
179 | |
180 ParameterInfo[] mips = mi.GetParameters(); | |
181 | |
182 if (mips.Length != ps.Length) | |
183 continue; | |
184 | |
185 bool equal = true; | |
186 | |
187 for (int i = 0; equal && i < ps.Length; i++) | |
188 equal = ps[i].ParameterType == mips[i].ParameterType; | |
189 | |
190 if (equal) | |
191 { | |
192 EmitHelper emit = Context.MethodBuilder.Emitter; | |
193 | |
194 for (int i = -1; i < ps.Length; i++) | |
195 emit.ldarg(i + 1); | |
196 | |
197 emit.callvirt(mi); | |
198 | |
199 if (Context.ReturnValue != null) | |
200 emit.stloc(Context.ReturnValue); | |
201 | |
202 return true; | |
203 } | |
204 } | |
205 } | |
206 | |
207 return false; | |
208 } | |
209 } | |
210 } |