Mercurial > pub > bltoolkit
comparison Source/Aspects/Builders/OverloadAspectBuilder.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.Collections.Generic; | |
| 3 using System.Reflection; | |
| 4 using System.Reflection.Emit; | |
| 5 | |
| 6 using BLToolkit.Properties; | |
| 7 using BLToolkit.Reflection; | |
| 8 using BLToolkit.Reflection.Emit; | |
| 9 using BLToolkit.TypeBuilder; | |
| 10 using BLToolkit.TypeBuilder.Builders; | |
| 11 | |
| 12 namespace BLToolkit.Aspects.Builders | |
| 13 { | |
| 14 public class OverloadAspectBuilder: AbstractTypeBuilderBase | |
| 15 { | |
| 16 private readonly string _overloadedMethodName; | |
| 17 private readonly Type[] _parameterTypes; | |
| 18 | |
| 19 public OverloadAspectBuilder(string overloadedMethodName, Type[] parameterTypes) | |
| 20 { | |
| 21 _overloadedMethodName = overloadedMethodName; | |
| 22 _parameterTypes = parameterTypes; | |
| 23 } | |
| 24 | |
| 25 public override int GetPriority(BuildContext context) | |
| 26 { | |
| 27 return TypeBuilderConsts.Priority.OverloadAspect; | |
| 28 } | |
| 29 | |
| 30 public override bool IsCompatible(BuildContext context, IAbstractTypeBuilder typeBuilder) | |
| 31 { | |
| 32 if (context.IsBuildStep) | |
| 33 return false; | |
| 34 | |
| 35 AbstractTypeBuilderList list = new AbstractTypeBuilderList(2); | |
| 36 | |
| 37 list.Add(this); | |
| 38 list.Add(typeBuilder); | |
| 39 | |
| 40 BuildStep step = context.Step; | |
| 41 | |
| 42 try | |
| 43 { | |
| 44 context.Step = BuildStep.Build; | |
| 45 | |
| 46 return typeBuilder.IsApplied(context, list); | |
| 47 } | |
| 48 finally | |
| 49 { | |
| 50 context.Step = step; | |
| 51 } | |
| 52 } | |
| 53 | |
| 54 public override bool IsApplied(BuildContext context, AbstractTypeBuilderList builders) | |
| 55 { | |
| 56 if (context == null) throw new ArgumentNullException("context"); | |
| 57 | |
| 58 return context.IsBuildStep && context.BuildElement == BuildElement.AbstractMethod; | |
| 59 } | |
| 60 | |
| 61 protected override void BuildAbstractMethod() | |
| 62 { | |
| 63 MethodInfo currentMethod = Context.CurrentMethod; | |
| 64 string methodName = _overloadedMethodName ?? currentMethod.Name; | |
| 65 MethodInfo overloadedMethod = GetOverloadedMethod(methodName); | |
| 66 | |
| 67 if (overloadedMethod == null) | |
| 68 { | |
| 69 throw new TypeBuilderException(string.Format( | |
| 70 Resources.OverloadAspectBuilder_NoOverloadedMethod, | |
| 71 Context.Type.FullName, methodName)); | |
| 72 } | |
| 73 | |
| 74 EmitHelper emit = Context.MethodBuilder.Emitter; | |
| 75 List<ParameterInfo> parameters = new List<ParameterInfo>(currentMethod.GetParameters()); | |
| 76 | |
| 77 if (!overloadedMethod.IsStatic) | |
| 78 emit.ldarg_0.end(); | |
| 79 | |
| 80 foreach (ParameterInfo param in overloadedMethod.GetParameters()) | |
| 81 { | |
| 82 ParameterInfo currentMethodParameter = null; | |
| 83 foreach (ParameterInfo p in parameters) | |
| 84 { | |
| 85 if (p.Name != param.Name) | |
| 86 continue; | |
| 87 | |
| 88 currentMethodParameter = p; | |
| 89 parameters.Remove(p); | |
| 90 break; | |
| 91 } | |
| 92 | |
| 93 if (currentMethodParameter != null) | |
| 94 { | |
| 95 emit.ldarg(currentMethodParameter); | |
| 96 } | |
| 97 else | |
| 98 { | |
| 99 Type type = param.ParameterType; | |
| 100 bool isRef = false; | |
| 101 | |
| 102 if (type.IsByRef) | |
| 103 { | |
| 104 type = type.GetElementType(); | |
| 105 isRef = true; | |
| 106 } | |
| 107 | |
| 108 if (type.IsValueType && !type.IsPrimitive) | |
| 109 { | |
| 110 LocalBuilder localBuilder = emit.DeclareLocal(type); | |
| 111 | |
| 112 emit | |
| 113 .ldloca (localBuilder) | |
| 114 .initobj (type) | |
| 115 ; | |
| 116 | |
| 117 if (isRef) | |
| 118 emit.ldloca (localBuilder); | |
| 119 else | |
| 120 emit.ldloc (localBuilder); | |
| 121 | |
| 122 } | |
| 123 else | |
| 124 { | |
| 125 if ((param.Attributes & ParameterAttributes.HasDefault) == 0 || | |
| 126 !emit.LoadWellKnownValue(param.DefaultValue)) | |
| 127 { | |
| 128 emit.LoadInitValue(type); | |
| 129 } | |
| 130 | |
| 131 if (isRef) | |
| 132 { | |
| 133 LocalBuilder localBuilder = emit.DeclareLocal(type); | |
| 134 | |
| 135 emit | |
| 136 .stloc (localBuilder) | |
| 137 .ldloca (localBuilder) | |
| 138 ; | |
| 139 } | |
| 140 } | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 // Finally, call the method we override. | |
| 145 // | |
| 146 if (overloadedMethod.IsStatic || overloadedMethod.IsFinal) | |
| 147 emit.call (overloadedMethod); | |
| 148 else | |
| 149 emit.callvirt (overloadedMethod); | |
| 150 | |
| 151 if (currentMethod.ReturnType != typeof(void)) | |
| 152 emit.stloc(Context.ReturnValue); | |
| 153 } | |
| 154 | |
| 155 private MethodInfo GetOverloadedMethod(string methodName) | |
| 156 { | |
| 157 MethodInfo currentMethod = Context.CurrentMethod; | |
| 158 MethodInfo bestMatch = null; | |
| 159 int bestMatchParametersCount = -1; | |
| 160 ParameterInfo[] currentMethodParameters = currentMethod.GetParameters(); | |
| 161 | |
| 162 if (_parameterTypes != null) | |
| 163 { | |
| 164 bestMatch = Context.Type.GetMethod(methodName, _parameterTypes); | |
| 165 return bestMatch != null && MatchParameters(currentMethodParameters, bestMatch.GetParameters()) >= 0? bestMatch: null; | |
| 166 } | |
| 167 | |
| 168 const BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Instance| BindingFlags.Public | BindingFlags.NonPublic; | |
| 169 | |
| 170 foreach (MethodInfo m in Context.Type.GetMethods(bindingFlags)) | |
| 171 { | |
| 172 if (m.IsPrivate || m.Name != methodName || m.IsGenericMethod != currentMethod.IsGenericMethod) | |
| 173 continue; | |
| 174 | |
| 175 if (!TypeHelper.CompareParameterTypes(m.ReturnType, currentMethod.ReturnType)) | |
| 176 continue; | |
| 177 | |
| 178 if (m.IsDefined(typeof(OverloadAttribute), true)) | |
| 179 continue; | |
| 180 | |
| 181 ParameterInfo[] overloadedMethodParameters = m.GetParameters(); | |
| 182 if (overloadedMethodParameters.Length <= bestMatchParametersCount) | |
| 183 continue; | |
| 184 | |
| 185 int matchedParameters = MatchParameters(overloadedMethodParameters, currentMethodParameters); | |
| 186 if (matchedParameters <= bestMatchParametersCount) | |
| 187 continue; | |
| 188 | |
| 189 bestMatchParametersCount = matchedParameters; | |
| 190 bestMatch = m; | |
| 191 } | |
| 192 | |
| 193 return bestMatch; | |
| 194 } | |
| 195 | |
| 196 private static int MatchParameters(ParameterInfo[] parametersToMatch, ParameterInfo[] existingParameters) | |
| 197 { | |
| 198 int matchedParameters = 0; | |
| 199 List<ParameterInfo> existingParametersList = new List<ParameterInfo>(existingParameters); | |
| 200 foreach (ParameterInfo param in parametersToMatch) | |
| 201 { | |
| 202 foreach (ParameterInfo existing in existingParametersList) | |
| 203 { | |
| 204 if (existing.Name != param.Name) | |
| 205 continue; | |
| 206 | |
| 207 if (!TypeHelper.CompareParameterTypes(param.ParameterType, existing.ParameterType)) | |
| 208 return -1; | |
| 209 | |
| 210 ++matchedParameters; | |
| 211 existingParametersList.Remove(existing); | |
| 212 break; | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 return matchedParameters; | |
| 217 } | |
| 218 } | |
| 219 } |
