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