annotate Source/Aspects/Builders/MixinAspectBuilder.cs @ 9:1e85f66cf767 default tip

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