Mercurial > pub > bltoolkit
comparison Source/TypeBuilder/Builders/InstanceTypeBuilder.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.Properties; | |
| 6 using BLToolkit.Reflection; | |
| 7 using BLToolkit.Reflection.Emit; | |
| 8 | |
| 9 namespace BLToolkit.TypeBuilder.Builders | |
| 10 { | |
| 11 class InstanceTypeBuilder : DefaultTypeBuilder | |
| 12 { | |
| 13 public InstanceTypeBuilder(Type instanceType, bool isObjectHolder) | |
| 14 { | |
| 15 _instanceType = instanceType; | |
| 16 _isObjectHolder = isObjectHolder; | |
| 17 } | |
| 18 | |
| 19 public InstanceTypeBuilder(Type propertyType, Type instanceType, bool isObjectHolder) | |
| 20 { | |
| 21 _propertyType = propertyType; | |
| 22 _instanceType = instanceType; | |
| 23 _isObjectHolder = isObjectHolder; | |
| 24 } | |
| 25 | |
| 26 private readonly bool _isObjectHolder; | |
| 27 | |
| 28 private readonly Type _propertyType; | |
| 29 public Type PropertyType | |
| 30 { | |
| 31 get { return _propertyType; } | |
| 32 } | |
| 33 | |
| 34 private readonly Type _instanceType; | |
| 35 public Type InstanceType | |
| 36 { | |
| 37 get { return _instanceType; } | |
| 38 } | |
| 39 | |
| 40 public override bool IsApplied(BuildContext context, AbstractTypeBuilderList builders) | |
| 41 { | |
| 42 if (context == null) throw new ArgumentNullException("context"); | |
| 43 | |
| 44 return | |
| 45 base.IsApplied(context, builders) && | |
| 46 context.CurrentProperty != null && | |
| 47 context.CurrentProperty.GetIndexParameters().Length == 0 && | |
| 48 (PropertyType == null || | |
| 49 TypeHelper.IsSameOrParent(PropertyType, context.CurrentProperty.PropertyType)); | |
| 50 } | |
| 51 | |
| 52 protected override Type GetFieldType() | |
| 53 { | |
| 54 return InstanceType; | |
| 55 } | |
| 56 | |
| 57 protected override Type GetObjectType() | |
| 58 { | |
| 59 return IsObjectHolder? Context.CurrentProperty.PropertyType: base.GetObjectType(); | |
| 60 } | |
| 61 | |
| 62 protected override bool IsObjectHolder | |
| 63 { | |
| 64 get { return _isObjectHolder && Context.CurrentProperty.PropertyType.IsClass; } | |
| 65 } | |
| 66 | |
| 67 protected override void BuildAbstractGetter() | |
| 68 { | |
| 69 var field = GetField(); | |
| 70 var emit = Context.MethodBuilder.Emitter; | |
| 71 var propertyType = Context.CurrentProperty.PropertyType; | |
| 72 var getter = GetGetter(); | |
| 73 | |
| 74 if (InstanceType.IsValueType) emit.ldarg_0.ldflda(field); | |
| 75 else emit.ldarg_0.ldfld (field); | |
| 76 | |
| 77 Type memberType; | |
| 78 | |
| 79 if (getter is PropertyInfo) | |
| 80 { | |
| 81 var pi = ((PropertyInfo)getter); | |
| 82 | |
| 83 if (InstanceType.IsValueType) emit.call (pi.GetGetMethod()); | |
| 84 else emit.callvirt(pi.GetGetMethod()); | |
| 85 | |
| 86 memberType = pi.PropertyType; | |
| 87 } | |
| 88 else if (getter is FieldInfo) | |
| 89 { | |
| 90 var fi = (FieldInfo)getter; | |
| 91 | |
| 92 emit.ldfld(fi); | |
| 93 | |
| 94 memberType = fi.FieldType; | |
| 95 } | |
| 96 else | |
| 97 { | |
| 98 var mi = (MethodInfo)getter; | |
| 99 var pi = mi.GetParameters(); | |
| 100 | |
| 101 for (var k = 0; k < pi.Length; k++) | |
| 102 { | |
| 103 var p = pi[k]; | |
| 104 | |
| 105 if (p.IsDefined(typeof(ParentAttribute), true)) | |
| 106 { | |
| 107 // Parent - set this. | |
| 108 // | |
| 109 emit.ldarg_0.end(); | |
| 110 | |
| 111 if (!TypeHelper.IsSameOrParent(p.ParameterType, Context.Type)) | |
| 112 emit.castclass(p.ParameterType); | |
| 113 } | |
| 114 else if (p.IsDefined(typeof (PropertyInfoAttribute), true)) | |
| 115 { | |
| 116 // PropertyInfo. | |
| 117 // | |
| 118 emit.ldsfld(GetPropertyInfoField()).end(); | |
| 119 } | |
| 120 else | |
| 121 throw new TypeBuilderException(string.Format( | |
| 122 Resources.TypeBuilder_UnknownParameterType, | |
| 123 mi.Name, mi.DeclaringType.FullName, p.Name)); | |
| 124 | |
| 125 } | |
| 126 | |
| 127 if (InstanceType.IsValueType) emit.call (mi); | |
| 128 else emit.callvirt(mi); | |
| 129 | |
| 130 memberType = mi.ReturnType; | |
| 131 } | |
| 132 | |
| 133 if (propertyType.IsValueType) | |
| 134 { | |
| 135 if (memberType.IsValueType == false) | |
| 136 emit.CastFromObject(propertyType); | |
| 137 } | |
| 138 else | |
| 139 { | |
| 140 if (memberType != propertyType) | |
| 141 emit.castclass(propertyType); | |
| 142 } | |
| 143 | |
| 144 emit.stloc(Context.ReturnValue); | |
| 145 } | |
| 146 | |
| 147 protected override void BuildAbstractSetter() | |
| 148 { | |
| 149 var field = GetField(); | |
| 150 var emit = Context.MethodBuilder.Emitter; | |
| 151 var propertyType = Context.CurrentProperty.PropertyType; | |
| 152 var setter = GetSetter(); | |
| 153 | |
| 154 if (InstanceType.IsValueType) emit.ldarg_0.ldflda(field); | |
| 155 else emit.ldarg_0.ldfld (field); | |
| 156 | |
| 157 if (setter is PropertyInfo) | |
| 158 { | |
| 159 var pi = ((PropertyInfo)setter); | |
| 160 | |
| 161 emit.ldarg_1.end(); | |
| 162 | |
| 163 if (propertyType.IsValueType && !pi.PropertyType.IsValueType) | |
| 164 emit.box(propertyType); | |
| 165 | |
| 166 if (InstanceType.IsValueType) emit.call (pi.GetSetMethod()); | |
| 167 else emit.callvirt(pi.GetSetMethod()); | |
| 168 } | |
| 169 else if (setter is FieldInfo) | |
| 170 { | |
| 171 var fi = (FieldInfo)setter; | |
| 172 | |
| 173 emit.ldarg_1.end(); | |
| 174 | |
| 175 if (propertyType.IsValueType && !fi.FieldType.IsValueType) | |
| 176 emit.box(propertyType); | |
| 177 | |
| 178 emit.stfld(fi); | |
| 179 } | |
| 180 else | |
| 181 { | |
| 182 var mi = (MethodInfo)setter; | |
| 183 var pi = mi.GetParameters(); | |
| 184 var gotValueParam = false; | |
| 185 | |
| 186 for (var k = 0; k < pi.Length; k++) | |
| 187 { | |
| 188 var p = pi[k]; | |
| 189 | |
| 190 if (p.IsDefined(typeof (ParentAttribute), true)) | |
| 191 { | |
| 192 // Parent - set this. | |
| 193 // | |
| 194 emit.ldarg_0.end(); | |
| 195 | |
| 196 if (!TypeHelper.IsSameOrParent(p.ParameterType, Context.Type)) | |
| 197 emit.castclass(p.ParameterType); | |
| 198 } | |
| 199 else if (p.IsDefined(typeof (PropertyInfoAttribute), true)) | |
| 200 { | |
| 201 // PropertyInfo. | |
| 202 // | |
| 203 emit.ldsfld(GetPropertyInfoField()).end(); | |
| 204 } | |
| 205 else if (!gotValueParam) | |
| 206 { | |
| 207 // This must be a value. | |
| 208 // | |
| 209 emit.ldarg_1.end(); | |
| 210 | |
| 211 if (propertyType.IsValueType && !p.ParameterType.IsValueType) | |
| 212 emit.box(propertyType); | |
| 213 | |
| 214 gotValueParam = true; | |
| 215 } | |
| 216 else | |
| 217 throw new TypeBuilderException(string.Format( | |
| 218 Resources.TypeBuilder_UnknownParameterType, | |
| 219 mi.Name, mi.DeclaringType.FullName, p.Name)); | |
| 220 } | |
| 221 | |
| 222 if (InstanceType.IsValueType) emit.call(mi); | |
| 223 else emit.callvirt(mi); | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 private MemberInfo GetGetter() | |
| 228 { | |
| 229 const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; | |
| 230 | |
| 231 var propertyType = Context.CurrentProperty.PropertyType; | |
| 232 var fields = InstanceType.GetFields(bindingFlags); | |
| 233 | |
| 234 foreach (var field in fields) | |
| 235 { | |
| 236 var attrs = field.GetCustomAttributes(typeof(GetValueAttribute), true); | |
| 237 | |
| 238 if (attrs.Length > 0 && TypeHelper.IsSameOrParent(field.FieldType, propertyType)) | |
| 239 return field; | |
| 240 } | |
| 241 | |
| 242 var props = InstanceType.GetProperties(bindingFlags); | |
| 243 | |
| 244 foreach (var prop in props) | |
| 245 { | |
| 246 var attrs = prop.GetCustomAttributes(typeof(GetValueAttribute), true); | |
| 247 | |
| 248 if (attrs.Length > 0 && TypeHelper.IsSameOrParent(prop.PropertyType, propertyType)) | |
| 249 return prop; | |
| 250 } | |
| 251 | |
| 252 foreach (var field in fields) | |
| 253 if (field.Name == "Value" && TypeHelper.IsSameOrParent(field.FieldType, propertyType)) | |
| 254 return field; | |
| 255 | |
| 256 foreach (var prop in props) | |
| 257 if (prop.Name == "Value" && TypeHelper.IsSameOrParent(prop.PropertyType, propertyType)) | |
| 258 return prop; | |
| 259 | |
| 260 var method = TypeHelper.GetMethod(InstanceType, false, "GetValue", bindingFlags); | |
| 261 | |
| 262 if (method != null && TypeHelper.IsSameOrParent(propertyType, method.ReturnType)) | |
| 263 return method; | |
| 264 | |
| 265 throw new TypeBuilderException(string.Format( | |
| 266 Resources.TypeBuilder_CannotGetGetter, InstanceType.FullName, | |
| 267 propertyType.FullName, Context.CurrentProperty.Name, Context.Type.FullName)); | |
| 268 } | |
| 269 | |
| 270 private MemberInfo GetSetter() | |
| 271 { | |
| 272 const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; | |
| 273 | |
| 274 var propertyType = Context.CurrentProperty.PropertyType; | |
| 275 var fields = InstanceType.GetFields(bindingFlags); | |
| 276 | |
| 277 foreach (var field in fields) | |
| 278 { | |
| 279 var attrs = field.GetCustomAttributes(typeof(SetValueAttribute), true); | |
| 280 | |
| 281 if (attrs.Length > 0 && TypeHelper.IsSameOrParent(field.FieldType, propertyType)) | |
| 282 return field; | |
| 283 } | |
| 284 | |
| 285 var props = InstanceType.GetProperties(bindingFlags); | |
| 286 | |
| 287 foreach (var prop in props) | |
| 288 { | |
| 289 var attrs = prop.GetCustomAttributes(typeof(SetValueAttribute), true); | |
| 290 | |
| 291 if (attrs.Length > 0 && TypeHelper.IsSameOrParent(prop.PropertyType, propertyType)) | |
| 292 return prop; | |
| 293 } | |
| 294 | |
| 295 foreach (var field in fields) | |
| 296 if (field.Name == "Value" && TypeHelper.IsSameOrParent(field.FieldType, propertyType)) | |
| 297 return field; | |
| 298 | |
| 299 foreach (var prop in props) | |
| 300 if (prop.Name == "Value" && TypeHelper.IsSameOrParent(prop.PropertyType, propertyType)) | |
| 301 return prop; | |
| 302 | |
| 303 var method = TypeHelper.GetMethod(InstanceType, false, "SetValue", bindingFlags); | |
| 304 | |
| 305 if (method != null && method.ReturnType == typeof(void)) | |
| 306 return method; | |
| 307 | |
| 308 throw new TypeBuilderException(string.Format( | |
| 309 Resources.TypeBuilder_CannotGetSetter, InstanceType.FullName, | |
| 310 propertyType.FullName, Context.CurrentProperty.Name, Context.Type.FullName)); | |
| 311 } | |
| 312 } | |
| 313 } |
