From 17702b465d647fe787204ea5c1e139c3974179fb Mon Sep 17 00:00:00 2001 From: cneuwirt Date: Thu, 15 Nov 2007 10:45:03 +0000 Subject: [PATCH] Create a PropertyDescriptor class to collection property information and simplify IL generation. git-svn-id: https://svn.castleproject.org/svn/castle/trunk@4487 73e77b4c-caa6-f847-a29a-24ab75ae54b6 --- .../Attributes/AttributesUtil.cs | 111 +++++++ .../DictionaryAdapterKeyPrefixAttribute.cs | 12 +- .../DictionaryAdapterPropertyBinderAttribute.cs | 5 +- .../Attributes/DictionaryComponentAttribute.cs | 14 +- .../Attributes/DictionaryKeyAttribute.cs | 12 +- .../DictionaryKeySubstitutionAttribute.cs | 12 +- .../Attributes/DictionaryStringValuesAttribute.cs | 19 +- ...stle.Components.DictionaryAdapter-vs2005.csproj | 2 + .../DefaultPropertyGetter.cs | 16 +- .../DictionaryAdapterFactory.cs | 354 +++++++-------------- .../IDictionaryAdapterFactory.cs | 4 +- .../IDictionaryKeyBuilder.cs | 3 +- .../IDictionaryPropertyGetter.cs | 5 +- .../IDictionaryPropertySetter.cs | 5 +- .../PropertyDescriptor.cs | 210 ++++++++++++ Components/DictionaryAdapter/Changes.txt | 2 + 16 files changed, 487 insertions(+), 299 deletions(-) create mode 100644 Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/AttributesUtil.cs create mode 100644 Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/PropertyDescriptor.cs diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/AttributesUtil.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/AttributesUtil.cs new file mode 100644 index 000000000..6531425bb --- /dev/null +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/AttributesUtil.cs @@ -0,0 +1,111 @@ +// Copyright 2004-2007 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System; + using System.Collections.Generic; + using System.Reflection; + + /// + /// Helper class for retrieving attributes. + /// + public static class AttributesUtil + { + /// + /// Gets the type attribute. + /// + /// The type. + /// The type attribute. + public static T GetTypeAttribute(Type type) where T : class + { + T attribute = GetAttribute(type); + + if (attribute == null) + { + foreach (Type baseInterface in type.GetInterfaces()) + { + attribute = GetTypeAttribute(baseInterface); + if (attribute != null) + { + break; + } + } + } + + return attribute; + } + + /// + /// Gets the attribute. + /// + /// The member. + /// The member attribute. + public static T GetAttribute(MemberInfo member) where T : class + { + object[] attributes = member.GetCustomAttributes(typeof(T), false); + if (attributes.Length > 0) + { + return (T)attributes[0]; + } + return null; + } + + /// + /// Gets the type attributes. + /// + /// The type. + /// The type attributes. + public static List GetTypeAttributes(Type type) + { + List attributes = GetAttributes(type); + + if (attributes == null) + { + foreach (Type baseInterface in type.GetInterfaces()) + { + attributes = GetTypeAttributes(baseInterface); + if (attributes != null) + { + break; + } + } + } + + return attributes; + } + + /// + /// Gets the attributes. + /// + /// The member. + /// The member attributes. + public static List GetAttributes(MemberInfo member) + { + List attributes = null; + object[] custom = member.GetCustomAttributes(typeof(T), false); + + if (custom.Length > 0) + { + attributes = new List(); + foreach (T builder in custom) + { + attributes.Add(builder); + } + } + + return attributes; + } + } +} \ No newline at end of file diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryAdapterKeyPrefixAttribute.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryAdapterKeyPrefixAttribute.cs index b4d201460..e7bbac56b 100644 --- a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryAdapterKeyPrefixAttribute.cs +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryAdapterKeyPrefixAttribute.cs @@ -16,7 +16,6 @@ namespace Castle.Components.DictionaryAdapter { using System; using System.Collections; - using System.Reflection; /// /// Assigns a prefix to the keyed properties of an interface. @@ -51,15 +50,8 @@ namespace Castle.Components.DictionaryAdapter set { keyPrefix = value; } } - /// - /// Apply the prefix to the key. - /// - /// The dictionary. - /// The key. - /// The source property. - /// The prefixed key. - String IDictionaryKeyBuilder.Apply( - IDictionary dictionary, String key, PropertyInfo property) + String IDictionaryKeyBuilder.GetKey(IDictionary dictionary, String key, + PropertyDescriptor property) { return keyPrefix + key; } diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryAdapterPropertyBinderAttribute.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryAdapterPropertyBinderAttribute.cs index 555fe488c..3dd6fdd52 100644 --- a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryAdapterPropertyBinderAttribute.cs +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryAdapterPropertyBinderAttribute.cs @@ -17,7 +17,6 @@ using System; namespace Castle.Components.DictionaryAdapter { using System.Collections; - using System.Reflection; /// /// Allows the user to convert the values in the dictionary into a different type on access. @@ -45,7 +44,7 @@ namespace Castle.Components.DictionaryAdapter object IDictionaryPropertyGetter.GetPropertyValue( IDictionaryAdapterFactory factory, IDictionary dictionary, - string key, object storedValue, PropertyInfo property) + string key, object storedValue, PropertyDescriptor property) { return binder.ConvertFromDictionary(storedValue); } @@ -56,7 +55,7 @@ namespace Castle.Components.DictionaryAdapter object IDictionaryPropertySetter.SetPropertyValue( IDictionaryAdapterFactory factory, IDictionary dictionary, - string key, object value, PropertyInfo property) + string key, object value, PropertyDescriptor property) { return binder.ConvertFromInterface(value); } diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryComponentAttribute.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryComponentAttribute.cs index 6a77e8ecc..ba22edbfb 100644 --- a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryComponentAttribute.cs +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryComponentAttribute.cs @@ -16,7 +16,6 @@ namespace Castle.Components.DictionaryAdapter { using System; using System.Collections; - using System.Reflection; /// /// Identifies a property should be represented as a nested component. @@ -54,8 +53,8 @@ namespace Castle.Components.DictionaryAdapter #region IDictionaryKeyBuilder Members - string IDictionaryKeyBuilder.Apply( - IDictionary dictionary, string key, PropertyInfo property) + string IDictionaryKeyBuilder.GetKey(IDictionary dictionary, string key, + PropertyDescriptor property) { return prefix ?? key + "_"; } @@ -66,13 +65,16 @@ namespace Castle.Components.DictionaryAdapter object IDictionaryPropertyGetter.GetPropertyValue( IDictionaryAdapterFactory factory, IDictionary dictionary, - string key, object storedValue, PropertyInfo property) + string key, object storedValue, PropertyDescriptor property) { if (storedValue == null) { + PropertyDescriptor descriptor = + new PropertyDescriptor(property.Property); + descriptor.AddKeyBuilder(new DictionaryAdapterKeyPrefixAttribute(key)); + return factory.GetAdapter( - property.PropertyType, dictionary, - new DictionaryAdapterKeyPrefixAttribute(key)); + property.Property.PropertyType, dictionary, descriptor); } return storedValue; diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryKeyAttribute.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryKeyAttribute.cs index 7b411adda..4b3a3263d 100644 --- a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryKeyAttribute.cs +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryKeyAttribute.cs @@ -16,7 +16,6 @@ namespace Castle.Components.DictionaryAdapter { using System; using System.Collections; - using System.Reflection; /// /// Assignes a specific dictionary key. @@ -35,15 +34,8 @@ namespace Castle.Components.DictionaryAdapter this.key = key; } - /// - /// Apply the replacement to the key. - /// - /// The dictionary. - /// The key. - /// The source property. - /// The updated key. - String IDictionaryKeyBuilder.Apply( - IDictionary dictionary, String key, PropertyInfo property) + String IDictionaryKeyBuilder.GetKey(IDictionary dictionary, String key, + PropertyDescriptor property) { return this.key; } diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryKeySubstitutionAttribute.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryKeySubstitutionAttribute.cs index a78e3c1d2..089b4fec7 100644 --- a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryKeySubstitutionAttribute.cs +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryKeySubstitutionAttribute.cs @@ -16,7 +16,6 @@ namespace Castle.Components.DictionaryAdapter { using System; using System.Collections; - using System.Reflection; /// /// Substitutes part of key with another string. @@ -38,15 +37,8 @@ namespace Castle.Components.DictionaryAdapter this.newValue = newValue; } - /// - /// Apply the replacement to the key. - /// - /// The dictionary. - /// The key. - /// The source property. - /// The updated key. - String IDictionaryKeyBuilder.Apply( - IDictionary dictionary, String key, PropertyInfo property) + String IDictionaryKeyBuilder.GetKey(IDictionary dictionary, String key, + PropertyDescriptor property) { return key.Replace(oldValue, newValue); } diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryStringValuesAttribute.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryStringValuesAttribute.cs index 004fa4472..6b9bd2115 100644 --- a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryStringValuesAttribute.cs +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Attributes/DictionaryStringValuesAttribute.cs @@ -16,7 +16,6 @@ namespace Castle.Components.DictionaryAdapter { using System; using System.Collections; - using System.Reflection; /// /// Converts all properties to strings. @@ -25,14 +24,30 @@ namespace Castle.Components.DictionaryAdapter AllowMultiple = false, Inherited = true)] public class DictionaryStringValuesAttribute : Attribute, IDictionaryPropertySetter { + private string format; + + /// + /// Gets or sets the format. + /// + /// The format. + public string Format + { + get { return format; } + set { format = value; } + } + #region IDictionaryPropertySetter Members object IDictionaryPropertySetter.SetPropertyValue( IDictionaryAdapterFactory factory, IDictionary dictionary, - string key, object value, PropertyInfo property) + string key, object value, PropertyDescriptor property) { if (value != null) { + if (!string.IsNullOrEmpty(format)) + { + return String.Format(format, value); + } return value.ToString(); } return value; diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Castle.Components.DictionaryAdapter-vs2005.csproj b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Castle.Components.DictionaryAdapter-vs2005.csproj index 8a1e38472..29933650b 100644 --- a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Castle.Components.DictionaryAdapter-vs2005.csproj +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/Castle.Components.DictionaryAdapter-vs2005.csproj @@ -36,6 +36,7 @@ + @@ -53,6 +54,7 @@ + diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/DefaultPropertyGetter.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/DefaultPropertyGetter.cs index 1089355fe..62b191446 100644 --- a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/DefaultPropertyGetter.cs +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/DefaultPropertyGetter.cs @@ -14,9 +14,9 @@ namespace Castle.Components.DictionaryAdapter { + using System; using System.Collections; using System.ComponentModel; - using System.Reflection; /// /// Manages conversion between property values. @@ -40,21 +40,23 @@ namespace Castle.Components.DictionaryAdapter /// The dictionary. /// The key. /// The stored value. - /// The property info. + /// The property. /// The effective property value. public object GetPropertyValue(IDictionaryAdapterFactory factory, IDictionary dictionary, string key, - object storedValue, PropertyInfo property) + object storedValue, PropertyDescriptor property) { - if (storedValue != null && - !property.PropertyType.IsInstanceOfType(storedValue)) + Type propertyType = property.Property.PropertyType; + + if (storedValue != null && !propertyType.IsInstanceOfType(storedValue)) { - TypeConverter converter = TypeDescriptor.GetConverter(property.PropertyType); - if (converter != null && converter.CanConvertFrom(storedValue.GetType())) + TypeConverter converter = TypeDescriptor.GetConverter(propertyType); + if (converter != null && converter.CanConvertFrom(storedValue.GetType())) { return converter.ConvertFrom(storedValue); } } + return storedValue; } } diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/DictionaryAdapterFactory.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/DictionaryAdapterFactory.cs index 40142585f..fe0afe8eb 100644 --- a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/DictionaryAdapterFactory.cs +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/DictionaryAdapterFactory.cs @@ -63,15 +63,15 @@ namespace Castle.Components.DictionaryAdapter /// /// The typed interface. /// The underlying source of properties. - /// The dictionary key builder. + /// The property descriptor. /// An implementation of the typed interface bound to the dictionary. /// /// The type represented by T must be an interface with properties. /// public object GetAdapter(Type type, IDictionary dictionary, - IDictionaryKeyBuilder keyBuilder) + PropertyDescriptor descriptor) { - return InternalGetAdapter(type, dictionary, keyBuilder); + return InternalGetAdapter(type, dictionary, descriptor); } /// @@ -104,10 +104,10 @@ namespace Castle.Components.DictionaryAdapter #endregion - #region Dynamic Type Building + #region Dynamic Type Generation private object InternalGetAdapter(Type type, IDictionary dictionary, - IDictionaryKeyBuilder keyBuilder) + PropertyDescriptor descriptor) { if (!type.IsInterface) { @@ -121,10 +121,10 @@ namespace Castle.Components.DictionaryAdapter if (adapterAssembly == null) { TypeBuilder typeBuilder = CreateTypeBuilder(type, appDomain, adapterAssemblyName); - adapterAssembly = CreateAdapterAssembly(type, typeBuilder, dictionary); + adapterAssembly = CreateAdapterAssembly(type, typeBuilder); } - return GetExistingAdapter(type, adapterAssembly, dictionary, keyBuilder); + return GetExistingAdapter(type, adapterAssembly, dictionary, descriptor); } private static TypeBuilder CreateTypeBuilder(Type type, AppDomain appDomain, @@ -147,31 +147,27 @@ namespace Castle.Components.DictionaryAdapter return typeBuilder; } - private static Assembly CreateAdapterAssembly( - Type type, TypeBuilder typeBuilder, IDictionary dictionary) + private static Assembly CreateAdapterAssembly(Type type, TypeBuilder typeBuilder) { FieldBuilder factoryField = typeBuilder.DefineField( "factory", typeof(DictionaryAdapterFactory), FieldAttributes.Private); FieldBuilder dictionaryField = typeBuilder.DefineField( "dictionary", typeof(IDictionary), FieldAttributes.Private); - FieldBuilder keyBuilderField = typeBuilder.DefineField( - "keyBuilder", typeof(IDictionaryKeyBuilder), FieldAttributes.Private); + FieldBuilder descriptorField = typeBuilder.DefineField( + "descriptor", typeof(PropertyDescriptor), FieldAttributes.Private); FieldBuilder propertyMapField = typeBuilder.DefineField( - "propertyMap", typeof(Dictionary), + "propertyMap", typeof(Dictionary), FieldAttributes.Private | FieldAttributes.Static); CreateAdapterConstructor(typeBuilder, factoryField, dictionaryField, - keyBuilderField); + descriptorField); - Dictionary propertyMap = GetPropertyInfoMap(type, dictionary); + Dictionary propertyMap = GetPropertyDescriptors(type); - foreach(KeyValuePair property in propertyMap) + foreach(KeyValuePair descriptor in propertyMap) { - String key = (String) property.Value[1]; - PropertyInfo propertyInfo = (PropertyInfo) property.Value[0]; CreateAdapterProperty(typeBuilder, factoryField, dictionaryField, - keyBuilderField, propertyMapField, key, - propertyInfo); + descriptorField, propertyMapField, descriptor.Value); } Type adapterType = typeBuilder.CreateType(); @@ -189,7 +185,7 @@ namespace Castle.Components.DictionaryAdapter private static void CreateAdapterConstructor( TypeBuilder typeBuilder, FieldInfo factoryField, - FieldInfo dictionaryField, FieldInfo keyBuilderField) + FieldInfo dictionaryField, FieldInfo descriptorField) { ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor( MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.Standard, @@ -200,7 +196,7 @@ namespace Castle.Components.DictionaryAdapter }); constructorBuilder.DefineParameter(1, ParameterAttributes.None, "factory"); constructorBuilder.DefineParameter(2, ParameterAttributes.None, "dictionary"); - constructorBuilder.DefineParameter(3, ParameterAttributes.None, "keyBuilder"); + constructorBuilder.DefineParameter(3, ParameterAttributes.None, "descriptor"); ILGenerator ilGenerator = constructorBuilder.GetILGenerator(); @@ -217,7 +213,7 @@ namespace Castle.Components.DictionaryAdapter ilGenerator.Emit(OpCodes.Stfld, dictionaryField); ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldarg_3); - ilGenerator.Emit(OpCodes.Stfld, keyBuilderField); + ilGenerator.Emit(OpCodes.Stfld, descriptorField); ilGenerator.Emit(OpCodes.Ret); } @@ -227,14 +223,15 @@ namespace Castle.Components.DictionaryAdapter private static void CreateAdapterProperty( TypeBuilder typeBuilder, FieldInfo factoryField, - FieldInfo dictionaryField, FieldInfo keyBuilderField, - FieldInfo propertyMapField, String key, PropertyInfo property) + FieldInfo dictionaryField, FieldInfo descriptorField, + FieldInfo propertyMapField, PropertyDescriptor descriptor) { + PropertyInfo property = descriptor.Property; PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(property.Name, property.Attributes, property.PropertyType, null); - MethodAttributes propertyMethodAttributes = + MethodAttributes propAttribs = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual; @@ -242,58 +239,46 @@ namespace Castle.Components.DictionaryAdapter { CreatePropertyGetMethod( typeBuilder, factoryField, dictionaryField, - keyBuilderField, propertyMapField, propertyBuilder, - key, property, propertyMethodAttributes); + descriptorField, propertyMapField, propertyBuilder, + descriptor, propAttribs); } if (property.CanWrite) { CreatePropertySetMethod( typeBuilder, factoryField, dictionaryField, - keyBuilderField, propertyMapField, propertyBuilder, - key, property, propertyMethodAttributes); + descriptorField, propertyMapField, propertyBuilder, + descriptor, propAttribs); } } private static void PreparePropertyMethod( - PropertyInfo property, String key, FieldInfo dictionaryField, - FieldInfo propertyMapField, FieldInfo keyBuilderField, - ILGenerator propILGenerator, Label start, - out LocalBuilder propertyInfo) + PropertyDescriptor descriptor, FieldInfo dictionaryField, + FieldInfo propertyMapField, FieldInfo descriptorField, + ILGenerator propILGenerator, out LocalBuilder descriptorLocal) { propILGenerator.DeclareLocal(typeof(String)); propILGenerator.DeclareLocal(typeof(object)); - propILGenerator.DeclareLocal(typeof(object[])); + descriptorLocal = propILGenerator.DeclareLocal(typeof(PropertyDescriptor)); - propertyInfo = propILGenerator.DeclareLocal(typeof(PropertyInfo)); - - // propertyDesc = propertyMap[key] + // key = propertyInfo.Name + propILGenerator.Emit(OpCodes.Ldstr, descriptor.Property.Name); + propILGenerator.Emit(OpCodes.Stloc_0); + + // descriptor = propertyMap[key] propILGenerator.Emit(OpCodes.Ldsfld, propertyMapField); - propILGenerator.Emit(OpCodes.Ldstr, property.Name); + propILGenerator.Emit(OpCodes.Ldstr, descriptor.Property.Name); propILGenerator.Emit(OpCodes.Callvirt, PropertyMapGetItem); - propILGenerator.Emit(OpCodes.Stloc_2); - - // propertyInfo = (PropertyInfo) propertyDesc[0] - propILGenerator.Emit(OpCodes.Ldloc_2); - propILGenerator.Emit(OpCodes.Ldc_I4_0); - propILGenerator.Emit(OpCodes.Ldelem_Ref); - propILGenerator.Emit(OpCodes.Castclass, typeof(PropertyInfo)); - propILGenerator.Emit(OpCodes.Stloc_S, propertyInfo); - - propILGenerator.Emit(OpCodes.Ldstr, key); - propILGenerator.Emit(OpCodes.Stloc_0); - - propILGenerator.Emit(OpCodes.Ldarg_0); - propILGenerator.Emit(OpCodes.Ldfld, keyBuilderField); - propILGenerator.Emit(OpCodes.Brfalse_S, start); + propILGenerator.Emit(OpCodes.Stloc_S, descriptorLocal); - propILGenerator.Emit(OpCodes.Ldarg_0); - propILGenerator.Emit(OpCodes.Ldfld, keyBuilderField); + // key = descriptor.GetKey(dictionary, key, descriptor) + propILGenerator.Emit(OpCodes.Ldloc_S, descriptorLocal); propILGenerator.Emit(OpCodes.Ldarg_0); propILGenerator.Emit(OpCodes.Ldfld, dictionaryField); propILGenerator.Emit(OpCodes.Ldloc_0); - propILGenerator.Emit(OpCodes.Ldloc_S, propertyInfo); - propILGenerator.Emit(OpCodes.Callvirt, PropertyKeyBuilder); + propILGenerator.Emit(OpCodes.Ldarg_0); + propILGenerator.Emit(OpCodes.Ldfld, descriptorField); + propILGenerator.Emit(OpCodes.Callvirt, DescriptorGetKey); propILGenerator.Emit(OpCodes.Stloc_0); } @@ -303,74 +288,59 @@ namespace Castle.Components.DictionaryAdapter private static void CreatePropertyGetMethod( TypeBuilder typeBuilder, FieldInfo factoryField, - FieldInfo dictionaryField, FieldInfo keyBuilderField, + FieldInfo dictionaryField, FieldInfo descriptorField, FieldInfo propertyMapField, PropertyBuilder propertyBuilder, - String key, PropertyInfo property, - MethodAttributes propertyMethodAttributes) + PropertyDescriptor descriptor, MethodAttributes propAttribs) { MethodBuilder getMethodBuilder = typeBuilder.DefineMethod( - "get_" + property.Name, propertyMethodAttributes, - property.PropertyType, null); + "get_" + descriptor.Property.Name, propAttribs, + descriptor.Property.PropertyType, null); ILGenerator getILGenerator = getMethodBuilder.GetILGenerator(); - Label getValue = getILGenerator.DefineLabel(); - Label checkForNull = getILGenerator.DefineLabel(); Label returnDefault = getILGenerator.DefineLabel(); Label storeResult = getILGenerator.DefineLabel(); Label loadResult = getILGenerator.DefineLabel(); + LocalBuilder descriptorLocal; - LocalBuilder propertyInfo; - PreparePropertyMethod(property, key, dictionaryField, propertyMapField, - keyBuilderField, getILGenerator, - getValue, out propertyInfo); - LocalBuilder result = getILGenerator.DeclareLocal(property.PropertyType); - LocalBuilder getter = - getILGenerator.DeclareLocal(typeof(IDictionaryPropertyGetter)); + PreparePropertyMethod( + descriptor, dictionaryField, propertyMapField, + descriptorField, getILGenerator, out descriptorLocal); + LocalBuilder result = getILGenerator.DeclareLocal( + descriptor.Property.PropertyType); - // value = dictionary[name] - getILGenerator.MarkLabel(getValue); + // value = dictionary[key] getILGenerator.Emit(OpCodes.Ldarg_0); getILGenerator.Emit(OpCodes.Ldfld, dictionaryField); getILGenerator.Emit(OpCodes.Ldloc_0); getILGenerator.Emit(OpCodes.Callvirt, DictionaryGetItem); getILGenerator.Emit(OpCodes.Stloc_1); - // propertyGetter = (IDictionaryPropertyGetter) propertyDesc[1] - getILGenerator.Emit(OpCodes.Ldloc_2); - getILGenerator.Emit(OpCodes.Ldc_I4_2); - getILGenerator.Emit(OpCodes.Ldelem_Ref); - getILGenerator.Emit(OpCodes.Castclass, typeof(IDictionaryPropertyGetter)); - getILGenerator.Emit(OpCodes.Stloc_S, getter); - - getILGenerator.Emit(OpCodes.Ldloc_S, getter); - getILGenerator.Emit(OpCodes.Brfalse_S, checkForNull); - - // gettter.GetPropertyValue(factory, dictionary, key, storedValue, propertyInfo) - getILGenerator.Emit(OpCodes.Ldloc_S, getter); + // value = descriptor.GetPropertyValue(factory, dictionary, key, value, descriptor) + getILGenerator.Emit(OpCodes.Ldloc_S, descriptorLocal); getILGenerator.Emit(OpCodes.Ldarg_0); getILGenerator.Emit(OpCodes.Ldfld, factoryField); getILGenerator.Emit(OpCodes.Ldarg_0); getILGenerator.Emit(OpCodes.Ldfld, dictionaryField); getILGenerator.Emit(OpCodes.Ldloc_0); getILGenerator.Emit(OpCodes.Ldloc_1); - getILGenerator.Emit(OpCodes.Ldloc_S, propertyInfo); - getILGenerator.Emit(OpCodes.Callvirt, PropertyValueGetter); + getILGenerator.Emit(OpCodes.Ldarg_0); + getILGenerator.Emit(OpCodes.Ldfld, descriptorField); + getILGenerator.Emit(OpCodes.Callvirt, DescriptorGetValue); getILGenerator.Emit(OpCodes.Stloc_1); // if (value == null) return null - getILGenerator.MarkLabel(checkForNull); getILGenerator.Emit(OpCodes.Ldloc_1); getILGenerator.Emit(OpCodes.Brfalse_S, returnDefault); - // return (PropertyType) value + // return (propertyInfo.PropertyType) value getILGenerator.Emit(OpCodes.Ldloc_1); - getILGenerator.Emit(OpCodes.Unbox_Any, property.PropertyType); + getILGenerator.Emit(OpCodes.Unbox_Any, descriptor.Property.PropertyType); getILGenerator.Emit(OpCodes.Br_S, storeResult); getILGenerator.MarkLabel(returnDefault); getILGenerator.Emit(OpCodes.Ldloca_S, result); - getILGenerator.Emit(OpCodes.Initobj, property.PropertyType); + getILGenerator.Emit(OpCodes.Initobj, descriptor.Property.PropertyType); getILGenerator.Emit(OpCodes.Br_S, loadResult); getILGenerator.MarkLabel(storeResult); @@ -391,57 +361,42 @@ namespace Castle.Components.DictionaryAdapter private static void CreatePropertySetMethod( TypeBuilder typeBuilder, FieldInfo factoryField, - FieldInfo dictionaryField, FieldInfo keyBuilderField, + FieldInfo dictionaryField, FieldInfo descriptorField, FieldInfo propertyMapField, PropertyBuilder propertyBuilder, - String key, PropertyInfo property, - MethodAttributes propertyMethodAttributes) + PropertyDescriptor descriptor, MethodAttributes propAttribs) { MethodBuilder setMethodBuilder = typeBuilder.DefineMethod( - "set_" + property.Name, propertyMethodAttributes, null, - new Type[] {property.PropertyType}); + "set_" + descriptor.Property.Name, propAttribs, null, + new Type[] {descriptor.Property.PropertyType}); ILGenerator setILGenerator = setMethodBuilder.GetILGenerator(); - Label setValue = setILGenerator.DefineLabel(); - Label storeResult = setILGenerator.DefineLabel(); - - LocalBuilder propertyInfo; - PreparePropertyMethod(property, key, dictionaryField, propertyMapField, - keyBuilderField, setILGenerator, - setValue, out propertyInfo); - LocalBuilder setter = - setILGenerator.DeclareLocal(typeof(IDictionaryPropertySetter)); - - // propertySetter = (IDictionaryPropertySetter) propertyDesc[1] - setILGenerator.MarkLabel(setValue); - setILGenerator.Emit(OpCodes.Ldloc_2); - setILGenerator.Emit(OpCodes.Ldc_I4_3); - setILGenerator.Emit(OpCodes.Ldelem_Ref); - setILGenerator.Emit(OpCodes.Castclass, typeof(IDictionaryPropertySetter)); - setILGenerator.Emit(OpCodes.Stloc_S, setter); + LocalBuilder descriptorLocal; + + PreparePropertyMethod( + descriptor, dictionaryField, propertyMapField, + descriptorField, setILGenerator, out descriptorLocal); setILGenerator.Emit(OpCodes.Ldarg_1); - if (property.PropertyType.IsValueType) + if (descriptor.Property.PropertyType.IsValueType) { - setILGenerator.Emit(OpCodes.Box, property.PropertyType); + setILGenerator.Emit(OpCodes.Box, descriptor.Property.PropertyType); } setILGenerator.Emit(OpCodes.Stloc_1); - setILGenerator.Emit(OpCodes.Ldloc_S, setter); - setILGenerator.Emit(OpCodes.Brfalse_S, storeResult); - - // settter.SetPropertyValue(factory, dictionary, key, value, propertyInfo) - setILGenerator.Emit(OpCodes.Ldloc_S, setter); + // value = descriptor.SetPropertyValue(factory, dictionary, key, value, descriptor) + setILGenerator.Emit(OpCodes.Ldloc_S, descriptorLocal); setILGenerator.Emit(OpCodes.Ldarg_0); setILGenerator.Emit(OpCodes.Ldfld, factoryField); setILGenerator.Emit(OpCodes.Ldarg_0); setILGenerator.Emit(OpCodes.Ldfld, dictionaryField); setILGenerator.Emit(OpCodes.Ldloc_0); setILGenerator.Emit(OpCodes.Ldloc_1); - setILGenerator.Emit(OpCodes.Ldloc_S, propertyInfo); - setILGenerator.Emit(OpCodes.Callvirt, PropertyValueSetter); + setILGenerator.Emit(OpCodes.Ldarg_0); + setILGenerator.Emit(OpCodes.Ldfld, descriptorField); + setILGenerator.Emit(OpCodes.Callvirt, DescriptorSetValue); setILGenerator.Emit(OpCodes.Stloc_1); - setILGenerator.MarkLabel(storeResult); + // dictionary[key] = value setILGenerator.Emit(OpCodes.Ldarg_0); setILGenerator.Emit(OpCodes.Ldfld, dictionaryField); setILGenerator.Emit(OpCodes.Ldloc_0); @@ -457,122 +412,38 @@ namespace Castle.Components.DictionaryAdapter #region Property Descriptors - private static Dictionary GetPropertyInfoMap( - Type type, IDictionary dictionary) + private static DictionaryGetPropertyDescriptors(Type type) { - Dictionary prop2key = new Dictionary(); - IDictionaryPropertySetter typeSetter = GetTypePropertySetter(type); + IDictionaryPropertyGetter typeGetter = + AttributesUtil.GetTypeAttribute(type); + IDictionaryPropertySetter typeSetter = + AttributesUtil.GetTypeAttribute(type); + Dictionary prop2key = + new Dictionary(); RecursivelyDiscoverProperties( type, delegate(PropertyInfo property) - { - String key = property.Name; - key = ApplyKeyBuilders(dictionary, key, property, - CollectMemberKeyBuilders(property)); - key = ApplyKeyBuilders(dictionary, key, property, - CollectTypeKeyBuilders(property.ReflectedType)); - - IDictionaryPropertyGetter getter = GetPropertyGetter(property); - IDictionaryPropertySetter setter = GetMemberPropertySetter(property); - - object[] propertyDescriptor = new object[] - {property, key, getter, setter ?? typeSetter}; - prop2key.Add(property.Name, propertyDescriptor); - }); - - return prop2key; - } - - private static String ApplyKeyBuilders(IDictionary dictionary, String key, - PropertyInfo property, - IEnumerable builders) - { - if (builders != null) - { - foreach(IDictionaryKeyBuilder builder in builders) - { - key = builder.Apply(dictionary, key, property); - } - } - return key; - } - - private static List CollectTypeKeyBuilders(Type type) - { - List builders = CollectMemberKeyBuilders(type); - - if (builders == null) - { - foreach(Type baseInterface in type.GetInterfaces()) - { - builders = CollectTypeKeyBuilders(baseInterface); - if (builders != null) - { - break; - } - } - } - - return builders; - } - - private static List CollectMemberKeyBuilders(MemberInfo member) - { - List builders = null; - object[] attributes = member.GetCustomAttributes(typeof(IDictionaryKeyBuilder), false); - - if (attributes.Length > 0) - { - builders = new List(); - foreach(IDictionaryKeyBuilder builder in attributes) - { - builders.Add(builder); - } - } - - return builders; - } - - private static IDictionaryPropertyGetter GetPropertyGetter(PropertyInfo property) - { - object[] getters = property.GetCustomAttributes(typeof(IDictionaryPropertyGetter), false); - if (getters.Length > 0) - { - return (IDictionaryPropertyGetter)getters[0]; - } - return DefaultPropertyGetter.Instance; - } + { + PropertyDescriptor descriptor = new PropertyDescriptor(property); - private static IDictionaryPropertySetter GetTypePropertySetter(Type type) - { - IDictionaryPropertySetter setter = GetMemberPropertySetter(type); + descriptor.Getter = AttributesUtil. + GetAttribute(property) + ?? typeGetter ?? DefaultPropertyGetter.Instance; + descriptor.Setter = AttributesUtil. + GetAttribute(property) + ?? typeSetter; - if (setter == null) - { - foreach (Type baseInterface in type.GetInterfaces()) - { - setter = GetMemberPropertySetter(baseInterface); - if (setter != null) - { - break; - } - } - } + descriptor.AddKeyBuilders( + AttributesUtil.GetAttributes(property)); + descriptor.AddKeyBuilders( + AttributesUtil.GetTypeAttributes(property.ReflectedType)); - return setter; - } + prop2key.Add(property.Name, descriptor); + }); - private static IDictionaryPropertySetter GetMemberPropertySetter(MemberInfo member) - { - object[] setters = member.GetCustomAttributes(typeof(IDictionaryPropertySetter), false); - if (setters.Length > 0) - { - return (IDictionaryPropertySetter)setters[0]; - } - return null; + return prop2key; } - private static void RecursivelyDiscoverProperties( Type currentType, Action onProperty) { @@ -611,11 +482,11 @@ namespace Castle.Components.DictionaryAdapter private object GetExistingAdapter(Type type, Assembly assembly, IDictionary dictionary, - IDictionaryKeyBuilder keyBuilder) + PropertyDescriptor descriptor) { String adapterFullTypeName = GetAdapterFullTypeName(type); return Activator.CreateInstance(assembly.GetType(adapterFullTypeName, true), - this, dictionary, keyBuilder); + this, dictionary, descriptor); } private static Assembly GetExistingAdapterAssembly(AppDomain appDomain, String assemblyName) @@ -637,29 +508,30 @@ namespace Castle.Components.DictionaryAdapter private static readonly MethodInfo PropertyMapGetItem = typeof(Dictionary).GetMethod("get_Item", new Type[] { typeof(String) }); - private static readonly MethodInfo PropertyKeyBuilder = - typeof(IDictionaryKeyBuilder).GetMethod( - "Apply", new Type[] + private static readonly MethodInfo DescriptorGetKey = + typeof(PropertyDescriptor).GetMethod( + "GetKey", new Type[] { - typeof(IDictionary), typeof(String), typeof(PropertyInfo) + typeof(IDictionary), typeof(String), + typeof(PropertyDescriptor) }); - private static readonly MethodInfo PropertyValueGetter = - typeof(IDictionaryPropertyGetter).GetMethod( + private static readonly MethodInfo DescriptorGetValue = + typeof(PropertyDescriptor).GetMethod( "GetPropertyValue", new Type[] { typeof(DictionaryAdapterFactory), typeof(IDictionary), typeof(String), typeof(object), - typeof(PropertyInfo) + typeof(PropertyDescriptor) }); - private static readonly MethodInfo PropertyValueSetter = - typeof(IDictionaryPropertySetter).GetMethod( + private static readonly MethodInfo DescriptorSetValue = + typeof(PropertyDescriptor).GetMethod( "SetPropertyValue", new Type[] { typeof(DictionaryAdapterFactory), typeof(IDictionary), typeof(String), typeof(object), - typeof(PropertyInfo) + typeof(PropertyDescriptor) }); #endregion diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryAdapterFactory.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryAdapterFactory.cs index 9817e7c63..1476a449b 100644 --- a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryAdapterFactory.cs +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryAdapterFactory.cs @@ -51,12 +51,12 @@ namespace Castle.Components.DictionaryAdapter /// /// The typed interface. /// The underlying source of properties. - /// The dictionary key builder. + /// The property descriptor. /// An implementation of the typed interface bound to the dictionary. /// /// The type represented by T must be an interface with properties. /// - object GetAdapter(Type type, IDictionary dictionary, IDictionaryKeyBuilder keyBuilder); + object GetAdapter(Type type, IDictionary dictionary, PropertyDescriptor descriptor); /// /// Gets a typed adapter bound to the . diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryKeyBuilder.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryKeyBuilder.cs index 2423d06db..eaf0fc8fc 100644 --- a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryKeyBuilder.cs +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryKeyBuilder.cs @@ -16,7 +16,6 @@ namespace Castle.Components.DictionaryAdapter { using System; using System.Collections; - using System.Reflection; /// /// Defines the contract for building typed dictionary keys. @@ -30,6 +29,6 @@ namespace Castle.Components.DictionaryAdapter /// The current key. /// The property. /// The updated key - String Apply(IDictionary dictionary, String key, PropertyInfo property); + String GetKey(IDictionary dictionary, String key, PropertyDescriptor property); } } \ No newline at end of file diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryPropertyGetter.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryPropertyGetter.cs index 32274ada5..b89ca2ea1 100644 --- a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryPropertyGetter.cs +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryPropertyGetter.cs @@ -15,7 +15,6 @@ namespace Castle.Components.DictionaryAdapter { using System.Collections; - using System.Reflection; /// /// Defines the contract for retrieving dictionary values. @@ -29,9 +28,9 @@ namespace Castle.Components.DictionaryAdapter /// The dictionary. /// The key. /// The stored value. - /// The property info. + /// The property. /// The effective property value. object GetPropertyValue(IDictionaryAdapterFactory factory, IDictionary dictionary, - string key, object storedValue, PropertyInfo property); + string key, object storedValue, PropertyDescriptor property); } } \ No newline at end of file diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryPropertySetter.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryPropertySetter.cs index 645378b4f..c25edf1e8 100644 --- a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryPropertySetter.cs +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/IDictionaryPropertySetter.cs @@ -15,7 +15,6 @@ namespace Castle.Components.DictionaryAdapter { using System.Collections; - using System.Reflection; /// /// Defines the contract for updating dictionary values. @@ -29,9 +28,9 @@ namespace Castle.Components.DictionaryAdapter /// The dictionary. /// The key. /// The stored value. - /// The property info. + /// The property. /// The stored property value. object SetPropertyValue(IDictionaryAdapterFactory factory, IDictionary dictionary, - string key, object value, PropertyInfo property); + string key, object value, PropertyDescriptor property); } } \ No newline at end of file diff --git a/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/PropertyDescriptor.cs b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/PropertyDescriptor.cs new file mode 100644 index 000000000..ba6ba1fde --- /dev/null +++ b/Components/DictionaryAdapter/Castle.Components.DictionaryAdapter/PropertyDescriptor.cs @@ -0,0 +1,210 @@ +// Copyright 2004-2007 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Components.DictionaryAdapter +{ + using System.Collections; + using System.Collections.Generic; + using System.Reflection; + + /// + /// Describes a dictionary property. + /// + public class PropertyDescriptor : IDictionaryKeyBuilder, + IDictionaryPropertyGetter, + IDictionaryPropertySetter + { + private readonly PropertyInfo property; + private IDictionaryPropertyGetter getter; + private IDictionaryPropertySetter setter; + private ICollection keyBuilders; + + /// + /// Initializes a new instance of the class. + /// + /// The property. + public PropertyDescriptor(PropertyInfo property) + { + this.property = property; + } + + /// + /// Gets the property. + /// + /// The property. + public PropertyInfo Property + { + get { return property; } + } + + /// + /// Gets or sets the key builders. + /// + /// The key builders. + public ICollection KeyBuilders + { + get { return keyBuilders; } + set { keyBuilders = value; } + } + + /// + /// Gets or sets the setter. + /// + /// The setter. + public IDictionaryPropertySetter Setter + { + get { return setter; } + set { setter = value; } + } + + /// + /// Gets or sets the getter. + /// + /// The getter. + public IDictionaryPropertyGetter Getter + { + get { return getter; } + set { getter = value; } + } + + #region IDictionaryKeyBuilder Members + + /// + /// Gets the key. + /// + /// The dictionary. + /// The key. + /// The descriptor. + /// + public string GetKey(IDictionary dictionary, string key, + PropertyDescriptor descriptor) + { + if (keyBuilders != null) + { + foreach(IDictionaryKeyBuilder builder in keyBuilders) + { + key = builder.GetKey(dictionary, key, this); + } + } + + if (descriptor != null) + { + key = descriptor.GetKey(dictionary, key, null); + } + + return key; + } + + /// + /// Adds the key builder. + /// + /// The builder. + public void AddKeyBuilder(IDictionaryKeyBuilder builder) + { + if (keyBuilders == null) + { + keyBuilders = new IDictionaryKeyBuilder[] { builder }; + } + else + { + keyBuilders.Add(builder); + } + } + + /// + /// Adds the key builders. + /// + /// The builders. + public void AddKeyBuilders(ICollection builders) + { + if (keyBuilders == null) + { + keyBuilders = builders; + } + else if (builders != null) + { + foreach (IDictionaryKeyBuilder builder in builders) + { + keyBuilders.Add(builder); + } + } + } + + #endregion + + #region IDictionaryPropertyGetter Members + + /// + /// Gets the property value. + /// + /// The factory. + /// The dictionary. + /// The key. + /// The stored value. + /// The descriptor. + /// + public object GetPropertyValue( + IDictionaryAdapterFactory factory, IDictionary dictionary, + string key, object storedValue, PropertyDescriptor descriptor) + { + if (getter != null) + { + storedValue = getter.GetPropertyValue( + factory, dictionary, key, storedValue, this); + } + + if (descriptor != null) + { + storedValue = descriptor.GetPropertyValue( + factory, dictionary, key, storedValue, null); + } + + return storedValue; + } + + #endregion + + #region IDictionaryPropertySetter Members + + /// + /// Sets the property value. + /// + /// The factory. + /// The dictionary. + /// The key. + /// The value. + /// The descriptor. + /// + public object SetPropertyValue( + IDictionaryAdapterFactory factory, IDictionary dictionary, + string key, object value, PropertyDescriptor descriptor) + { + if (setter != null) + { + value = setter.SetPropertyValue( + factory, dictionary, key, value, this); + } + + if (descriptor != null) + { + value = descriptor.SetPropertyValue( + factory, dictionary, key, value, null); + } + + return value; + } + + #endregion + } +} \ No newline at end of file diff --git a/Components/DictionaryAdapter/Changes.txt b/Components/DictionaryAdapter/Changes.txt index 57559fbf1..ca1a36b7a 100644 --- a/Components/DictionaryAdapter/Changes.txt +++ b/Components/DictionaryAdapter/Changes.txt @@ -1,6 +1,8 @@ RC 4 ==== +- Created PropertyDescriptor to simplify IL generation + - Refactored to generalize property getting and setting - Refactored to support general-purpose key modifications -- 2.11.4.GIT