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 }