Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
03/15/10 12:02:00 (15 years ago)
Author:
epitzer
Message:

add support for automatic serialization of fields and properties (#548)

Location:
trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable
Files:
3 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableClassAttribute.cs

    r3025 r3029  
    44using System.Linq;
    55
    6 namespace HeuristicLab.Persistence.Default.CompositeSerializers.Storable {
    7 
    8 
    9   /// <summary>
    10   /// Specifies which memebrs are selected for serialization by the StorableSerializer
    11   /// </summary>
    12   public enum StorableClassType {
    13 
    14     /// <summary>
    15     /// Serialize only fields and properties that have been marked
    16     /// with the [Storable] attribute. This is the default value.
    17     /// </summary>
    18     MarkedOnly,
    19 
    20     /// <summary>
    21     /// Serialize all fields but ignore the
    22     /// [Storable] attribute on properties.
    23     /// </summary>
    24     [Obsolete("not implemented yet")]
    25     AllFields,
    26 
    27     /// <summary>
    28     /// Serialize all properties but ignore the
    29     /// [Storable] attirbute on fields.
    30     /// </summary>
    31     [Obsolete("not implemented yet")]
    32     AllProperties,
    33 
    34     /// <summary>
    35     /// Serialize all fields and all properties
    36     /// but ignore the [Storable] on all members.
    37     /// </summary>
    38     [Obsolete("not implemnted yet")]
    39     AllFieldsAndAllProperties
    40   };
    41 
     6namespace HeuristicLab.Persistence.Default.CompositeSerializers.Storable { 
    427
    438  /// <summary>
  • trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableSerializer.cs

    r3025 r3029  
    1212  /// <summary>
    1313  /// Intended for serialization of all custom classes. Classes should have the
    14   /// <c>[StorableClass]</c> attribute set and a serialization mode set.
    15   /// Optionally selected fields and properties can be marked with the
    16   /// <c>[Storable]</c> attribute.
     14  /// <c>[StorableClass]</c> attribute set. The default mode is to serialize
     15  /// members with the <c>[Storable]</c> attribute set. Alternatively the
     16  /// storable mode can be set to <c>AllFields</c>, <c>AllProperties</c>
     17  /// or <c>AllFieldsAndAllProperties</c>.
    1718  /// </summary>
    18   [StorableClass]   
     19  [StorableClass]
    1920  public class StorableSerializer : ICompositeSerializer {
    20 
    2121
    2222    #region ICompositeSerializer implementation
     
    3030        GetStorableConstructor(type) == null)
    3131        return false;
    32       return IsEmptyOrStorableType(type, true);
     32      return StorableReflection.IsEmptyOrStorableType(type, true);
    3333    }
    3434
     
    3737        GetStorableConstructor(type) == null)
    3838        return "no default constructor and no storable constructor";
    39       if (!IsEmptyOrStorableType(type, true))
     39      if (!StorableReflection.IsEmptyOrStorableType(type, true))
    4040        return "class is not marked with the storable class attribute";
    4141      return "no reason";
     
    7171      while (iter.MoveNext()) {
    7272        memberDict.Add(iter.Current.Name, iter.Current);
    73       }     
     73      }
    7474      foreach (var accessor in GetStorableAccessors(instance)) {
    7575        if (memberDict.ContainsKey(accessor.Name)) {
     
    8484    #endregion
    8585
    86     #region constances & private data types
     86    #region constants & private data types
    8787
    8888    private const BindingFlags ALL_CONSTRUCTORS =
    8989      BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
    90 
    91     private const BindingFlags DECLARED_INSTANCE_MEMBERS =
    92       BindingFlags.Instance |
    93       BindingFlags.Public |
    94       BindingFlags.NonPublic |
    95       BindingFlags.DeclaredOnly;
    96 
    97     private sealed class StorableMemberInfo {
    98       public StorableAttribute Attribute { get; private set; }
    99       public MemberInfo MemberInfo { get; private set; }
    100       public string DisentangledName { get; private set; }
    101       public string FullyQualifiedMemberName {
    102         get {
    103           return new StringBuilder()
    104             .Append(MemberInfo.ReflectedType.FullName)
    105             .Append('.')
    106             .Append(MemberInfo.Name)
    107             .ToString();
    108         }
    109       }
    110       public StorableMemberInfo(StorableAttribute attribute, MemberInfo memberInfo) {
    111         this.Attribute = attribute;
    112         this.MemberInfo = memberInfo;
    113       }
    114       public override string ToString() {
    115         return new StringBuilder()
    116           .Append('[').Append(Attribute).Append(", ")
    117           .Append(MemberInfo).Append('}').ToString();
    118       }
    119       public void SetDisentangledName(string name) {
    120         DisentangledName = Attribute.Name ?? name;
    121       }
    122       public Type GetPropertyDeclaringBaseType() {
    123         return ((PropertyInfo)MemberInfo).GetGetMethod(true).GetBaseDefinition().DeclaringType;
    124       }
    125     }
    12690
    12791    private sealed class TypeQuery {
     
    141105
    142106    private MemberCache storableMemberCache = new MemberCache();
    143     private Dictionary<Type, ConstructorInfo> constructorCache = 
     107    private Dictionary<Type, ConstructorInfo> constructorCache =
    144108      new Dictionary<Type, ConstructorInfo>();
    145109
    146110    #endregion
    147111
    148     #region auxiliary attribute reflection tools
     112    #region attribute access
    149113
    150114    private IEnumerable<StorableMemberInfo> GetStorableMembers(Type type) {
     
    157121        if (storableMemberCache.ContainsKey(query))
    158122          return storableMemberCache[query];
    159         var storablesMembers = GenerateStorableMembers(type, inherited);
     123        var storablesMembers = StorableReflection.GenerateStorableMembers(type, inherited);
    160124        storableMemberCache[query] = storablesMembers;
    161125        return storablesMembers;
    162126      }
    163     }
    164 
    165     private static IEnumerable<StorableMemberInfo> GenerateStorableMembers(Type type, bool inherited) {
    166       var storableMembers = new List<StorableMemberInfo>();
    167       if (inherited && type.BaseType != null)
    168         storableMembers.AddRange(GenerateStorableMembers(type.BaseType, true));
    169       foreach (MemberInfo memberInfo in type.GetMembers(DECLARED_INSTANCE_MEMBERS)) {
    170         foreach (StorableAttribute attribute in memberInfo.GetCustomAttributes(typeof(StorableAttribute), false)) {
    171           storableMembers.Add(new StorableMemberInfo(attribute, memberInfo));
    172         }
    173       }
    174       return DisentangleNameMapping(storableMembers);
    175     }
    176 
    177     private IEnumerable<DataMemberAccessor> GetStorableAccessors(object obj) {
    178       foreach (var memberInfo in GetStorableMembers(obj.GetType()))
    179         yield return new DataMemberAccessor(
    180           memberInfo.MemberInfo,
    181           memberInfo.DisentangledName,
    182           memberInfo.Attribute.DefaultValue,
    183           obj);
    184     }
    185 
    186     private static IEnumerable<StorableMemberInfo> DisentangleNameMapping(
    187         IEnumerable<StorableMemberInfo> storableMemberInfos) {
    188       var nameGrouping = new Dictionary<string, List<StorableMemberInfo>>();
    189       foreach (StorableMemberInfo storable in storableMemberInfos) {
    190         if (!nameGrouping.ContainsKey(storable.MemberInfo.Name))
    191           nameGrouping[storable.MemberInfo.Name] = new List<StorableMemberInfo>();
    192         nameGrouping[storable.MemberInfo.Name].Add(storable);
    193       }
    194       var memberInfos = new List<StorableMemberInfo>();
    195       foreach (var storableMemberInfoGroup in nameGrouping.Values) {
    196         if (storableMemberInfoGroup.Count == 1) {
    197           storableMemberInfoGroup[0].SetDisentangledName(storableMemberInfoGroup[0].MemberInfo.Name);
    198           memberInfos.Add(storableMemberInfoGroup[0]);
    199         } else if (storableMemberInfoGroup[0].MemberInfo.MemberType == MemberTypes.Field) {
    200           foreach (var storableMemberInfo in storableMemberInfoGroup) {
    201             storableMemberInfo.SetDisentangledName(storableMemberInfo.FullyQualifiedMemberName);
    202             memberInfos.Add(storableMemberInfo);
    203           }
    204         } else {
    205           memberInfos.AddRange(MergePropertyAccessors(storableMemberInfoGroup));
    206         }
    207       }
    208       return memberInfos;
    209     }
    210 
    211     private static IEnumerable<StorableMemberInfo> MergePropertyAccessors(List<StorableMemberInfo> members) {
    212       var uniqueAccessors = new Dictionary<Type, StorableMemberInfo>();
    213       foreach (var member in members)
    214         uniqueAccessors[member.GetPropertyDeclaringBaseType()] = member;
    215       if (uniqueAccessors.Count == 1) {
    216         var storableMemberInfo = uniqueAccessors.Values.First();
    217         storableMemberInfo.SetDisentangledName(storableMemberInfo.MemberInfo.Name);
    218         yield return storableMemberInfo;
    219       } else {
    220         foreach (var attribute in uniqueAccessors.Values) {
    221           attribute.SetDisentangledName(attribute.FullyQualifiedMemberName);
    222           yield return attribute;
    223         }
    224       }
    225     }
    226 
    227     private static bool IsEmptyOrStorableType(Type type, bool recusrive) {
    228       if (IsEmptyType(type, recusrive)) return true;
    229       if (!HastStorableClassAttribute(type)) return false;
    230       return !recusrive || type.BaseType == null || IsEmptyOrStorableType(type.BaseType, true);
    231     }
    232 
    233     private static bool HastStorableClassAttribute(Type type) {
    234       return type.GetCustomAttributes(typeof(StorableClassAttribute), false).Length > 0;
    235     }
    236 
    237     private static bool IsEmptyType(Type type, bool recursive) {
    238       foreach (MemberInfo memberInfo in type.GetMembers(DECLARED_INSTANCE_MEMBERS)) {
    239         if (IsModifiableMember(memberInfo)) return false;
    240       }
    241       return !recursive || type.BaseType == null || IsEmptyType(type.BaseType, true);
    242     }
    243 
    244     private static bool IsModifiableMember(MemberInfo memberInfo) {
    245       return memberInfo.MemberType == MemberTypes.Field && IsModifiableField((FieldInfo)memberInfo) ||
    246                 memberInfo.MemberType == MemberTypes.Property && IsModifiableProperty((PropertyInfo)memberInfo);
    247     }
    248 
    249     private static bool IsModifiableField(FieldInfo fi) {
    250       return !fi.IsLiteral && !fi.IsInitOnly;
    251     }
    252 
    253     private static bool IsModifiableProperty(PropertyInfo pi) {
    254       return pi.CanWrite;
    255     }
     127    }   
    256128
    257129    private ConstructorInfo GetStorableConstructor(Type type) {
     
    273145    }
    274146
     147    private IEnumerable<DataMemberAccessor> GetStorableAccessors(object obj) {
     148      return GetStorableMembers(obj.GetType())
     149        .Select(mi => new DataMemberAccessor(mi.MemberInfo, mi.DisentangledName, mi.DefaultValue, obj));
     150    }
     151
    275152    #endregion
     153   
    276154  }
     155 
    277156}
Note: See TracChangeset for help on using the changeset viewer.