Mercurial > pub > bltoolkit
view Source/TypeBuilder/Builders/InstanceTypeBuilder.cs @ 4:f757da6161a1
!bug 100 + 2h fixed gregression
author | cin |
---|---|
date | Sun, 24 Aug 2014 17:57:42 +0400 |
parents | f990fcb411a9 |
children |
line wrap: on
line source
using System; using System.Reflection; using System.Reflection.Emit; using BLToolkit.Properties; using BLToolkit.Reflection; using BLToolkit.Reflection.Emit; namespace BLToolkit.TypeBuilder.Builders { class InstanceTypeBuilder : DefaultTypeBuilder { public InstanceTypeBuilder(Type instanceType, bool isObjectHolder) { _instanceType = instanceType; _isObjectHolder = isObjectHolder; } public InstanceTypeBuilder(Type propertyType, Type instanceType, bool isObjectHolder) { _propertyType = propertyType; _instanceType = instanceType; _isObjectHolder = isObjectHolder; } private readonly bool _isObjectHolder; private readonly Type _propertyType; public Type PropertyType { get { return _propertyType; } } private readonly Type _instanceType; public Type InstanceType { get { return _instanceType; } } public override bool IsApplied(BuildContext context, AbstractTypeBuilderList builders) { if (context == null) throw new ArgumentNullException("context"); return base.IsApplied(context, builders) && context.CurrentProperty != null && context.CurrentProperty.GetIndexParameters().Length == 0 && (PropertyType == null || TypeHelper.IsSameOrParent(PropertyType, context.CurrentProperty.PropertyType)); } protected override Type GetFieldType() { return InstanceType; } protected override Type GetObjectType() { return IsObjectHolder? Context.CurrentProperty.PropertyType: base.GetObjectType(); } protected override bool IsObjectHolder { get { return _isObjectHolder && Context.CurrentProperty.PropertyType.IsClass; } } protected override void BuildAbstractGetter() { var field = GetField(); var emit = Context.MethodBuilder.Emitter; var propertyType = Context.CurrentProperty.PropertyType; var getter = GetGetter(); if (InstanceType.IsValueType) emit.ldarg_0.ldflda(field); else emit.ldarg_0.ldfld (field); Type memberType; if (getter is PropertyInfo) { var pi = ((PropertyInfo)getter); if (InstanceType.IsValueType) emit.call (pi.GetGetMethod()); else emit.callvirt(pi.GetGetMethod()); memberType = pi.PropertyType; } else if (getter is FieldInfo) { var fi = (FieldInfo)getter; emit.ldfld(fi); memberType = fi.FieldType; } else { var mi = (MethodInfo)getter; var pi = mi.GetParameters(); for (var k = 0; k < pi.Length; k++) { var p = pi[k]; if (p.IsDefined(typeof(ParentAttribute), true)) { // Parent - set this. // emit.ldarg_0.end(); if (!TypeHelper.IsSameOrParent(p.ParameterType, Context.Type)) emit.castclass(p.ParameterType); } else if (p.IsDefined(typeof (PropertyInfoAttribute), true)) { // PropertyInfo. // emit.ldsfld(GetPropertyInfoField()).end(); } else throw new TypeBuilderException(string.Format( Resources.TypeBuilder_UnknownParameterType, mi.Name, mi.DeclaringType.FullName, p.Name)); } if (InstanceType.IsValueType) emit.call (mi); else emit.callvirt(mi); memberType = mi.ReturnType; } if (propertyType.IsValueType) { if (memberType.IsValueType == false) emit.CastFromObject(propertyType); } else { if (memberType != propertyType) emit.castclass(propertyType); } emit.stloc(Context.ReturnValue); } protected override void BuildAbstractSetter() { var field = GetField(); var emit = Context.MethodBuilder.Emitter; var propertyType = Context.CurrentProperty.PropertyType; var setter = GetSetter(); if (InstanceType.IsValueType) emit.ldarg_0.ldflda(field); else emit.ldarg_0.ldfld (field); if (setter is PropertyInfo) { var pi = ((PropertyInfo)setter); emit.ldarg_1.end(); if (propertyType.IsValueType && !pi.PropertyType.IsValueType) emit.box(propertyType); if (InstanceType.IsValueType) emit.call (pi.GetSetMethod()); else emit.callvirt(pi.GetSetMethod()); } else if (setter is FieldInfo) { var fi = (FieldInfo)setter; emit.ldarg_1.end(); if (propertyType.IsValueType && !fi.FieldType.IsValueType) emit.box(propertyType); emit.stfld(fi); } else { var mi = (MethodInfo)setter; var pi = mi.GetParameters(); var gotValueParam = false; for (var k = 0; k < pi.Length; k++) { var p = pi[k]; if (p.IsDefined(typeof (ParentAttribute), true)) { // Parent - set this. // emit.ldarg_0.end(); if (!TypeHelper.IsSameOrParent(p.ParameterType, Context.Type)) emit.castclass(p.ParameterType); } else if (p.IsDefined(typeof (PropertyInfoAttribute), true)) { // PropertyInfo. // emit.ldsfld(GetPropertyInfoField()).end(); } else if (!gotValueParam) { // This must be a value. // emit.ldarg_1.end(); if (propertyType.IsValueType && !p.ParameterType.IsValueType) emit.box(propertyType); gotValueParam = true; } else throw new TypeBuilderException(string.Format( Resources.TypeBuilder_UnknownParameterType, mi.Name, mi.DeclaringType.FullName, p.Name)); } if (InstanceType.IsValueType) emit.call(mi); else emit.callvirt(mi); } } private MemberInfo GetGetter() { const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; var propertyType = Context.CurrentProperty.PropertyType; var fields = InstanceType.GetFields(bindingFlags); foreach (var field in fields) { var attrs = field.GetCustomAttributes(typeof(GetValueAttribute), true); if (attrs.Length > 0 && TypeHelper.IsSameOrParent(field.FieldType, propertyType)) return field; } var props = InstanceType.GetProperties(bindingFlags); foreach (var prop in props) { var attrs = prop.GetCustomAttributes(typeof(GetValueAttribute), true); if (attrs.Length > 0 && TypeHelper.IsSameOrParent(prop.PropertyType, propertyType)) return prop; } foreach (var field in fields) if (field.Name == "Value" && TypeHelper.IsSameOrParent(field.FieldType, propertyType)) return field; foreach (var prop in props) if (prop.Name == "Value" && TypeHelper.IsSameOrParent(prop.PropertyType, propertyType)) return prop; var method = TypeHelper.GetMethod(InstanceType, false, "GetValue", bindingFlags); if (method != null && TypeHelper.IsSameOrParent(propertyType, method.ReturnType)) return method; throw new TypeBuilderException(string.Format( Resources.TypeBuilder_CannotGetGetter, InstanceType.FullName, propertyType.FullName, Context.CurrentProperty.Name, Context.Type.FullName)); } private MemberInfo GetSetter() { const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; var propertyType = Context.CurrentProperty.PropertyType; var fields = InstanceType.GetFields(bindingFlags); foreach (var field in fields) { var attrs = field.GetCustomAttributes(typeof(SetValueAttribute), true); if (attrs.Length > 0 && TypeHelper.IsSameOrParent(field.FieldType, propertyType)) return field; } var props = InstanceType.GetProperties(bindingFlags); foreach (var prop in props) { var attrs = prop.GetCustomAttributes(typeof(SetValueAttribute), true); if (attrs.Length > 0 && TypeHelper.IsSameOrParent(prop.PropertyType, propertyType)) return prop; } foreach (var field in fields) if (field.Name == "Value" && TypeHelper.IsSameOrParent(field.FieldType, propertyType)) return field; foreach (var prop in props) if (prop.Name == "Value" && TypeHelper.IsSameOrParent(prop.PropertyType, propertyType)) return prop; var method = TypeHelper.GetMethod(InstanceType, false, "SetValue", bindingFlags); if (method != null && method.ReturnType == typeof(void)) return method; throw new TypeBuilderException(string.Format( Resources.TypeBuilder_CannotGetSetter, InstanceType.FullName, propertyType.FullName, Context.CurrentProperty.Name, Context.Type.FullName)); } } }