- Timestamp:
- 05/17/11 11:22:15 (14 years ago)
- 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 24 24 using System.Linq; 25 25 using System.Reflection; 26 using System.Reflection.Emit;27 26 using System.Text; 28 27 using HeuristicLab.Persistence.Core; 28 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable.Descriptors; 29 29 using HeuristicLab.Persistence.Interfaces; 30 30 … … 41 41 public sealed class StorableSerializer : ICompositeSerializer { 42 42 43 private StorableClassAnalyzer analyzer; 44 43 45 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(); 48 47 } 48 49 49 [StorableConstructor] 50 50 private StorableSerializer(bool deserializing) : this() { } … … 68 68 /// </returns> 69 69 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; 74 78 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; 82 81 } 83 82 … … 92 91 public string JustifyRejection(Type type) { 93 92 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]"); 98 102 return sb.ToString(); 99 103 } … … 105 109 /// <returns>A list of storable components.</returns> 106 110 public IEnumerable<Tag> CreateMetaInfo(object o) { 107 InvokeHook(HookType.BeforeSerialization, o);108 111 return new Tag[] { }; 109 112 } … … 117 120 /// <returns>An enumerable of <see cref="Tag"/>s.</returns> 118 121 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); 122 124 } 123 125 } … … 131 133 public object CreateInstance(Type type, IEnumerable<Tag> metaInfo) { 132 134 try { 133 return GetConstructor(type)();135 return analyzer[type].CreateInstance(); 134 136 } catch (TargetInvocationException x) { 135 137 throw new PersistenceException( … … 146 148 /// <param name="type">The type.</param> 147 149 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)); 163 151 } 164 152 165 153 #endregion 166 154 167 #region constants & private data types168 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 #endregion190 191 #region caches192 193 private AccessorListCache accessorListCache;194 private AccessorCache accessorCache;195 private Dictionary<Type, Constructor> constructorCache;196 private Dictionary<HookDesignator, List<StorableReflection.Hook>> hookCache;197 198 #endregion199 200 #region attribute access201 202 private IEnumerable<DataMemberAccessor> GetStorableAccessors(Type type) {203 lock (accessorListCache) {204 if (accessorListCache.ContainsKey(type))205 return accessorListCache[type];206 var storableMembers = StorableReflection207 .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 true254 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 #endregion284 285 286 287 155 } 288 156
Note: See TracChangeset
for help on using the changeset viewer.