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