Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
05/17/11 11:22:15 (14 years ago)
Author:
epitzer
Message:

Streamline persistence reflection and store into persistable data structure for caching (#1530)

Location:
branches/PersistenceSpeedUp/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable
Files:
8 added
2 deleted
1 edited

Legend:

Unmodified
Added
Removed
  • branches/PersistenceSpeedUp/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableSerializer.cs

    r5445 r6214  
    2424using System.Linq;
    2525using System.Reflection;
    26 using System.Reflection.Emit;
    2726using System.Text;
    2827using HeuristicLab.Persistence.Core;
     28using HeuristicLab.Persistence.Default.CompositeSerializers.Storable.Descriptors;
    2929using HeuristicLab.Persistence.Interfaces;
    3030
     
    4141  public sealed class StorableSerializer : ICompositeSerializer {
    4242
     43    private StorableClassAnalyzer analyzer;
     44
    4345    public StorableSerializer() {
    44       accessorListCache = new AccessorListCache();
    45       accessorCache = new AccessorCache();
    46       constructorCache = new Dictionary<Type, Constructor>();
    47       hookCache = new Dictionary<HookDesignator, List<StorableReflection.Hook>>();
     46      analyzer = new StorableClassAnalyzer();
    4847    }
     48
    4949    [StorableConstructor]
    5050    private StorableSerializer(bool deserializing) : this() { }
     
    6868    /// </returns>
    6969    public bool CanSerialize(Type type) {
    70       bool markedStorable = StorableReflection.HasStorableClassAttribute(type);
    71       if (GetConstructor(type) == null)
    72         if (markedStorable)
    73           throw new Exception("[Storable] type has no default constructor and no [StorableConstructor]");
     70      TypeDescriptor desc = analyzer[type];
     71      if (desc.IsInvalid)
     72        return false;
     73      if (desc.HasDefaultConstructor)
     74        return true;
     75      else if (desc.IsStorableClass)
     76        if (desc.HasDefaultConstructor || desc.HasStorableConstructor)
     77          return true;
    7478        else
    75           return false;
    76       if (!StorableReflection.IsEmptyOrStorableType(type, true))
    77         if (markedStorable)
    78           throw new Exception("[Storable] type has non emtpy, non [Storable] base classes");
    79         else
    80           return false;
    81       return true;
     79          throw new PersistenceException("[Storable] type has no default constructor and no [StorableConstructor]");
     80      return false;
    8281    }
    8382
     
    9291    public string JustifyRejection(Type type) {
    9392      StringBuilder sb = new StringBuilder();
    94       if (GetConstructor(type) == null)
    95         sb.Append("class has no default constructor and no [StorableConstructor]");
    96       if (!StorableReflection.IsEmptyOrStorableType(type, true))
    97         sb.Append("class (or one of its bases) is not empty and not marked [Storable]; ");
     93      TypeDescriptor desc = analyzer[type];
     94      if (desc.IsInvalid)
     95        sb.Append("class is not marked [StorableClass] but has mutable members.");
     96      if (!desc.IsStorableClass)
     97        sb.Append("class is not marked [StorableClass]");
     98      if (!desc.HasDefaultConstructor)
     99        sb.Append("class has no default constructor");
     100      if (!desc.HasStorableConstructor)
     101        sb.Append("class has no [StorableConstructor]");
    98102      return sb.ToString();
    99103    }
     
    105109    /// <returns>A list of storable components.</returns>
    106110    public IEnumerable<Tag> CreateMetaInfo(object o) {
    107       InvokeHook(HookType.BeforeSerialization, o);
    108111      return new Tag[] { };
    109112    }
     
    117120    /// <returns>An enumerable of <see cref="Tag"/>s.</returns>
    118121    public IEnumerable<Tag> Decompose(object obj) {
    119       foreach (var accessor in GetStorableAccessors(obj.GetType())) {
    120         if (accessor.Get != null)
    121           yield return new Tag(accessor.Name, accessor.Get(obj));
     122      foreach (var kvp in analyzer[obj.GetType()].Decompose(obj)) {
     123        yield return new Tag(kvp.Key, kvp.Value);
    122124      }
    123125    }
     
    131133    public object CreateInstance(Type type, IEnumerable<Tag> metaInfo) {
    132134      try {
    133         return GetConstructor(type)();
     135        return analyzer[type].CreateInstance();
    134136      } catch (TargetInvocationException x) {
    135137        throw new PersistenceException(
     
    146148    /// <param name="type">The type.</param>
    147149    public void Populate(object instance, IEnumerable<Tag> objects, Type type) {
    148       var memberDict = new Dictionary<string, Tag>();
    149       IEnumerator<Tag> iter = objects.GetEnumerator();
    150       while (iter.MoveNext()) {
    151         memberDict.Add(iter.Current.Name, iter.Current);
    152       }
    153       foreach (var accessor in GetStorableAccessors(instance.GetType())) {
    154         if (accessor.Set != null) {
    155           if (memberDict.ContainsKey(accessor.Name)) {
    156             accessor.Set(instance, memberDict[accessor.Name].Value);
    157           } else if (accessor.DefaultValue != null) {
    158             accessor.Set(instance, accessor.DefaultValue);
    159           }
    160         }
    161       }
    162       InvokeHook(HookType.AfterDeserialization, instance);
     150      analyzer[type].Populate(instance, objects.ToDictionary(kvp => kvp.Name, kvp => kvp.Value));
    163151    }
    164152
    165153    #endregion
    166154
    167     #region constants & private data types
    168 
    169     private const BindingFlags ALL_CONSTRUCTORS =
    170       BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
    171 
    172     private static readonly object[] emptyArgs = new object[] { };
    173     private static readonly object[] trueArgs = new object[] { true };
    174 
    175     private sealed class HookDesignator {
    176       public Type Type { get; private set; }
    177       public HookType HookType { get; private set; }
    178       public HookDesignator() { }
    179       public HookDesignator(Type type, HookType hookType) {
    180         Type = type;
    181         HookType = HookType;
    182       }
    183     }
    184 
    185     private sealed class AccessorListCache : Dictionary<Type, IEnumerable<DataMemberAccessor>> { }
    186     private sealed class AccessorCache : Dictionary<MemberInfo, DataMemberAccessor> { }
    187     private delegate object Constructor();
    188 
    189     #endregion
    190 
    191     #region caches
    192 
    193     private AccessorListCache accessorListCache;
    194     private AccessorCache accessorCache;
    195     private Dictionary<Type, Constructor> constructorCache;
    196     private Dictionary<HookDesignator, List<StorableReflection.Hook>> hookCache;
    197 
    198     #endregion
    199 
    200     #region attribute access
    201 
    202     private IEnumerable<DataMemberAccessor> GetStorableAccessors(Type type) {
    203       lock (accessorListCache) {
    204         if (accessorListCache.ContainsKey(type))
    205           return accessorListCache[type];
    206         var storableMembers = StorableReflection
    207           .GenerateStorableMembers(type)
    208           .Select(mi => GetMemberAccessor(mi));
    209         accessorListCache[type] = storableMembers;
    210         return storableMembers;
    211       }
    212     }
    213 
    214     private DataMemberAccessor GetMemberAccessor(StorableMemberInfo mi) {
    215       lock (accessorCache) {
    216         if (accessorCache.ContainsKey(mi.MemberInfo))
    217           return new DataMemberAccessor(accessorCache[mi.MemberInfo], mi.DisentangledName, mi.DefaultValue);
    218         DataMemberAccessor dma = new DataMemberAccessor(mi.MemberInfo, mi.DisentangledName, mi.DefaultValue);
    219         accessorCache[mi.MemberInfo] = dma;
    220         return dma;
    221       }
    222     }
    223 
    224     private Constructor GetConstructor(Type type) {
    225       lock (constructorCache) {
    226         if (constructorCache.ContainsKey(type))
    227           return constructorCache[type];
    228         Constructor c = FindStorableConstructor(type) ?? GetDefaultConstructor(type);
    229         constructorCache.Add(type, c);
    230         return c;
    231       }
    232     }
    233 
    234     private Constructor GetDefaultConstructor(Type type) {
    235       ConstructorInfo ci = type.GetConstructor(ALL_CONSTRUCTORS, null, Type.EmptyTypes, null);
    236       if (ci == null)
    237         return null;
    238       DynamicMethod dm = new DynamicMethod("", typeof(object), null, type, true);
    239       ILGenerator ilgen = dm.GetILGenerator();
    240       ilgen.Emit(OpCodes.Newobj, ci);
    241       ilgen.Emit(OpCodes.Ret);
    242       return (Constructor)dm.CreateDelegate(typeof(Constructor));
    243     }
    244 
    245     private Constructor FindStorableConstructor(Type type) {
    246       foreach (ConstructorInfo ci in type.GetConstructors(ALL_CONSTRUCTORS)) {
    247         if (ci.GetCustomAttributes(typeof(StorableConstructorAttribute), false).Length > 0) {
    248           if (ci.GetParameters().Length != 1 ||
    249               ci.GetParameters()[0].ParameterType != typeof(bool))
    250             throw new PersistenceException("StorableConstructor must have exactly one argument of type bool");
    251           DynamicMethod dm = new DynamicMethod("", typeof(object), null, type, true);
    252           ILGenerator ilgen = dm.GetILGenerator();
    253           ilgen.Emit(OpCodes.Ldc_I4_1); // load true
    254           ilgen.Emit(OpCodes.Newobj, ci);
    255           ilgen.Emit(OpCodes.Ret);
    256           return (Constructor)dm.CreateDelegate(typeof(Constructor));
    257         }
    258       }
    259       return null;
    260     }
    261 
    262     private void InvokeHook(HookType hookType, object obj) {
    263       if (obj == null)
    264         throw new ArgumentNullException("Cannot invoke hooks on null");
    265       foreach (StorableReflection.Hook hook in GetHooks(hookType, obj.GetType())) {
    266         hook(obj);
    267       }
    268     }
    269 
    270     private IEnumerable<StorableReflection.Hook> GetHooks(HookType hookType, Type type) {
    271       lock (hookCache) {
    272         List<StorableReflection.Hook> hooks;
    273         var designator = new HookDesignator(type, hookType);
    274         hookCache.TryGetValue(designator, out hooks);
    275         if (hooks != null)
    276           return hooks;
    277         hooks = new List<StorableReflection.Hook>(StorableReflection.CollectHooks(hookType, type));
    278         hookCache.Add(designator, hooks);
    279         return hooks;
    280       }
    281     }
    282 
    283     #endregion
    284 
    285 
    286 
    287155  }
    288156
Note: See TracChangeset for help on using the changeset viewer.