Changeset 3025 for trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableSerializer.cs
- Timestamp:
- 03/15/10 00:00:12 (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableSerializer.cs
r3017 r3025 6 6 using System.Reflection; 7 7 using HeuristicLab.Persistence.Auxiliary; 8 using System.Text; 8 9 9 10 namespace HeuristicLab.Persistence.Default.CompositeSerializers.Storable { … … 18 19 public class StorableSerializer : ICompositeSerializer { 19 20 21 22 #region ICompositeSerializer implementation 23 20 24 public int Priority { 21 25 get { return 200; } … … 24 28 public bool CanSerialize(Type type) { 25 29 if (!ReflectionTools.HasDefaultConstructor(type) && 26 StorableConstructorAttribute.GetStorableConstructor(type) == null)30 GetStorableConstructor(type) == null) 27 31 return false; 28 return StorableClassAttribute.IsStorableType(type, true);32 return IsEmptyOrStorableType(type, true); 29 33 } 30 34 31 35 public string JustifyRejection(Type type) { 32 36 if (!ReflectionTools.HasDefaultConstructor(type) && 33 StorableConstructorAttribute.GetStorableConstructor(type) == null)37 GetStorableConstructor(type) == null) 34 38 return "no default constructor and no storable constructor"; 35 return "class or one of its base classes is not empty and has no [StorableClass] attribute"; 39 if (!IsEmptyOrStorableType(type, true)) 40 return "class is not marked with the storable class attribute"; 41 return "no reason"; 36 42 } 37 43 … … 42 48 43 49 public IEnumerable<Tag> Decompose(object obj) { 44 foreach (var accessor in StorableAttribute.GetStorableAccessors(obj)) {50 foreach (var accessor in GetStorableAccessors(obj)) { 45 51 yield return new Tag(accessor.Name, accessor.Get()); 46 52 } … … 51 57 public object CreateInstance(Type type, IEnumerable<Tag> metaInfo) { 52 58 try { 53 ConstructorInfo constructor = StorableConstructorAttribute.GetStorableConstructor(type);59 ConstructorInfo constructor = GetStorableConstructor(type); 54 60 return constructor != null ? constructor.Invoke(defaultArgs) : Activator.CreateInstance(type, true); 55 61 } catch (TargetInvocationException x) { … … 66 72 memberDict.Add(iter.Current.Name, iter.Current); 67 73 } 68 foreach (var accessor in StorableAttribute.GetStorableAccessors(instance)) {74 foreach (var accessor in GetStorableAccessors(instance)) { 69 75 if (memberDict.ContainsKey(accessor.Name)) { 70 76 accessor.Set(memberDict[accessor.Name].Value); … … 75 81 StorableHookAttribute.InvokeHook(HookType.AfterDeserialization, instance); 76 82 } 83 84 #endregion 85 86 #region constances & private data types 87 88 private const BindingFlags ALL_CONSTRUCTORS = 89 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 } 126 127 private sealed class TypeQuery { 128 public Type Type { get; private set; } 129 public bool Inherited { get; private set; } 130 public TypeQuery(Type type, bool inherited) { 131 this.Type = type; 132 this.Inherited = inherited; 133 } 134 } 135 136 private sealed class MemberCache : Dictionary<TypeQuery, IEnumerable<StorableMemberInfo>> { } 137 138 #endregion 139 140 #region caches 141 142 private MemberCache storableMemberCache = new MemberCache(); 143 private Dictionary<Type, ConstructorInfo> constructorCache = 144 new Dictionary<Type, ConstructorInfo>(); 145 146 #endregion 147 148 #region auxiliary attribute reflection tools 149 150 private IEnumerable<StorableMemberInfo> GetStorableMembers(Type type) { 151 return GetStorableMembers(type, true); 152 } 153 154 private IEnumerable<StorableMemberInfo> GetStorableMembers(Type type, bool inherited) { 155 lock (storableMemberCache) { 156 var query = new TypeQuery(type, inherited); 157 if (storableMemberCache.ContainsKey(query)) 158 return storableMemberCache[query]; 159 var storablesMembers = GenerateStorableMembers(type, inherited); 160 storableMemberCache[query] = storablesMembers; 161 return storablesMembers; 162 } 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 } 256 257 private ConstructorInfo GetStorableConstructor(Type type) { 258 lock (constructorCache) { 259 if (constructorCache.ContainsKey(type)) 260 return constructorCache[type]; 261 foreach (ConstructorInfo ci in type.GetConstructors(ALL_CONSTRUCTORS)) { 262 if (ci.GetCustomAttributes(typeof(StorableConstructorAttribute), false).Length > 0) { 263 if (ci.GetParameters().Length != 1 || 264 ci.GetParameters()[0].ParameterType != typeof(bool)) 265 throw new PersistenceException("StorableConstructor must have exactly one argument of type bool"); 266 constructorCache[type] = ci; 267 return ci; 268 } 269 } 270 constructorCache[type] = null; 271 return null; 272 } 273 } 274 275 #endregion 77 276 } 78 277 }
Note: See TracChangeset
for help on using the changeset viewer.