Changeset 3025 for trunk/sources/HeuristicLab.Persistence/3.3/Default
- Timestamp:
- 03/15/10 00:00:12 (14 years ago)
- Location:
- trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableAttribute.cs
r3017 r3025 60 60 return sb.ToString(); 61 61 } 62 63 private const BindingFlags instanceMembers =64 BindingFlags.Instance |65 BindingFlags.Public |66 BindingFlags.NonPublic |67 BindingFlags.DeclaredOnly;68 69 /// <summary>70 /// Encapsulate information about storable members of a class71 /// that have the storable attribute set.72 /// </summary>73 public sealed class StorableMemberInfo {74 75 /// <summary>76 /// Gets the [Storable] attribute itself.77 /// </summary>78 /// <value>The [Storable] attribute.</value>79 public StorableAttribute Attribute { get; private set; }80 81 /// <summary>82 /// Gets the .NET reflection MemberInfo.83 /// </summary>84 /// <value>The member info.</value>85 public MemberInfo MemberInfo { get; private set; }86 87 88 /// <summary>89 /// Gets disentangled name (i.e. unique access name regardless of90 /// type hierarchy.91 /// </summary>92 /// <value>The disentangled name.</value>93 public string DisentangledName { get; private set; }94 95 96 /// <summary>97 /// Gets the fully qualified member name.98 /// </summary>99 /// <value>The the fully qualified member name.</value>100 public string FullyQualifiedMemberName {101 get {102 return new StringBuilder()103 .Append(MemberInfo.ReflectedType.FullName)104 .Append('.')105 .Append(MemberInfo.Name)106 .ToString();107 }108 }109 110 internal StorableMemberInfo(StorableAttribute attribute, MemberInfo memberInfo) {111 this.Attribute = attribute;112 this.MemberInfo = memberInfo;113 }114 115 /// <summary>116 /// Returns a <see cref="System.String"/> that represents this instance.117 /// </summary>118 /// <returns>119 /// A <see cref="System.String"/> that represents this instance.120 /// </returns>121 public override string ToString() {122 return new StringBuilder()123 .Append('[').Append(Attribute).Append(", ")124 .Append(MemberInfo).Append('}').ToString();125 }126 127 internal void SetDisentangledName(string name) {128 DisentangledName = Attribute.Name ?? name;129 }130 131 /// <summary>132 /// Gets the delcaring type of the property.133 /// </summary>134 /// <returns></returns>135 public Type GetPropertyDeclaringBaseType() {136 return ((PropertyInfo)MemberInfo).GetGetMethod(true).GetBaseDefinition().DeclaringType;137 }138 }139 140 private sealed class TypeQuery {141 public Type Type { get; private set; }142 public bool Inherited { get; private set; }143 public TypeQuery(Type type, bool inherited) {144 this.Type = type;145 this.Inherited = inherited;146 }147 }148 149 private sealed class MemberCache : Dictionary<TypeQuery, IEnumerable<StorableMemberInfo>> { }150 151 private static MemberCache memberCache = new MemberCache();152 153 154 /// <summary>155 /// Get all fields and properties of a class that have the156 /// <c>[Storable]</c> attribute set.157 /// </summary>158 /// <param name="type">The type.</param>159 /// <returns>An enumerable of StorableMemberInfos.</returns>160 public static IEnumerable<StorableMemberInfo> GetStorableMembers(Type type) {161 return GetStorableMembers(type, true);162 }163 164 /// <summary>165 /// Get all fields and properties of a class that have the166 /// <c>[Storable]</c> attribute set.167 /// </summary>168 /// <param name="type">The type.</param>169 /// <param name="inherited">should storable members from base classes be included</param>170 /// <returns>An enumerable of StorableMemberInfos</returns>171 public static IEnumerable<StorableMemberInfo> GetStorableMembers(Type type, bool inherited) {172 lock (memberCache) {173 var query = new TypeQuery(type, inherited);174 if (memberCache.ContainsKey(query))175 return memberCache[query];176 var storablesMembers = GenerateStorableMembers(type, inherited);177 memberCache[query] = storablesMembers;178 return storablesMembers;179 }180 }181 182 private static IEnumerable<StorableMemberInfo> GenerateStorableMembers(Type type, bool inherited) {183 var storableMembers = new List<StorableMemberInfo>();184 if (inherited && type.BaseType != null)185 storableMembers.AddRange(GenerateStorableMembers(type.BaseType, true));186 foreach (MemberInfo memberInfo in type.GetMembers(instanceMembers)) {187 foreach (StorableAttribute attribute in memberInfo.GetCustomAttributes(typeof(StorableAttribute), false)) {188 storableMembers.Add(new StorableMemberInfo(attribute, memberInfo));189 }190 }191 return DisentangleNameMapping(storableMembers);192 }193 194 195 /// <summary>196 /// Get the associated accessors for all storable memebrs.197 /// </summary>198 /// <param name="obj">The object</param>199 /// <returns>An enumerable of storable accessors.</returns>200 public static IEnumerable<DataMemberAccessor> GetStorableAccessors(object obj) {201 foreach (var memberInfo in GetStorableMembers(obj.GetType()))202 yield return new DataMemberAccessor(203 memberInfo.MemberInfo,204 memberInfo.DisentangledName,205 memberInfo.Attribute.DefaultValue,206 obj);207 }208 209 private static IEnumerable<StorableMemberInfo> DisentangleNameMapping(210 IEnumerable<StorableMemberInfo> storableMemberInfos) {211 var nameGrouping = new Dictionary<string, List<StorableMemberInfo>>();212 foreach (StorableMemberInfo storable in storableMemberInfos) {213 if (!nameGrouping.ContainsKey(storable.MemberInfo.Name))214 nameGrouping[storable.MemberInfo.Name] = new List<StorableMemberInfo>();215 nameGrouping[storable.MemberInfo.Name].Add(storable);216 }217 var memberInfos = new List<StorableMemberInfo>();218 foreach (var storableMemberInfoGroup in nameGrouping.Values) {219 if (storableMemberInfoGroup.Count == 1) {220 storableMemberInfoGroup[0].SetDisentangledName(storableMemberInfoGroup[0].MemberInfo.Name);221 memberInfos.Add(storableMemberInfoGroup[0]);222 } else if (storableMemberInfoGroup[0].MemberInfo.MemberType == MemberTypes.Field) {223 foreach (var storableMemberInfo in storableMemberInfoGroup) {224 storableMemberInfo.SetDisentangledName(storableMemberInfo.FullyQualifiedMemberName);225 memberInfos.Add(storableMemberInfo);226 }227 } else {228 memberInfos.AddRange(MergePropertyAccessors(storableMemberInfoGroup));229 }230 }231 return memberInfos;232 }233 234 private static IEnumerable<StorableMemberInfo> MergePropertyAccessors(List<StorableMemberInfo> members) {235 var uniqueAccessors = new Dictionary<Type, StorableMemberInfo>();236 foreach (var member in members)237 uniqueAccessors[member.GetPropertyDeclaringBaseType()] = member;238 if (uniqueAccessors.Count == 1) {239 var storableMemberInfo = uniqueAccessors.Values.First();240 storableMemberInfo.SetDisentangledName(storableMemberInfo.MemberInfo.Name);241 yield return storableMemberInfo;242 } else {243 foreach (var attribute in uniqueAccessors.Values) {244 attribute.SetDisentangledName(attribute.FullyQualifiedMemberName);245 yield return attribute;246 }247 }248 }249 62 } 250 63 } -
trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableClassAttribute.cs
r3017 r3025 69 69 } 70 70 71 /// <summary>72 /// Check that the type is either empty i.e. has no fields or properties73 /// or conatins proper parameterization through the storable attribute.74 /// </summary>75 /// <param name="type">The type.</param>76 /// <param name="recusrive">if set to <c>true</c> recusrively checks class hierarchy.</param>77 /// <returns>78 /// <c>true</c> if the specified type is a storable type; otherwise, <c>false</c>.79 /// </returns>80 public static bool IsStorableType(Type type, bool recusrive) {81 if (IsEmptyType(type, recusrive))82 return true;83 StorableClassAttribute attribute = type84 .GetCustomAttributes(typeof(StorableClassAttribute), false)85 .Cast<StorableClassAttribute>().SingleOrDefault();86 if (attribute == null)87 return false;88 if (!recusrive || type.BaseType == null)89 return true;90 else91 return IsStorableType(type.BaseType, true);92 }93 94 private const BindingFlags allDeclaredMembers =95 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly;96 97 98 /// <summary>99 /// Determines whether the specified type has no fields or properties except100 /// readonly properties or constant fields.101 /// </summary>102 /// <param name="type">The type.</param>103 /// <param name="recursive">if set to <c>true</c> recursively check class hierarchy.</param>104 /// <returns>105 /// <c>true</c> if the specified type is empty; otherwise, <c>false</c>.106 /// </returns>107 public static bool IsEmptyType(Type type, bool recursive) {108 foreach (MemberInfo memberInfo in type.GetMembers(allDeclaredMembers)) {109 if (110 memberInfo.MemberType == MemberTypes.Field && IsModifiableField((FieldInfo)memberInfo) ||111 memberInfo.MemberType == MemberTypes.Property && IsModifiableProperty((PropertyInfo)memberInfo)) {112 return false;113 }114 }115 if (!recursive || type.BaseType == null)116 return true;117 else118 return IsEmptyType(type.BaseType, true);119 }120 121 private static bool IsModifiableField(FieldInfo fi) {122 return !fi.IsLiteral && !fi.IsInitOnly;123 }124 125 private static bool IsModifiableProperty(PropertyInfo pi) {126 return pi.CanWrite;127 }128 71 } 129 72 } 130 73 131 132 -
trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableConstructorAttribute.cs
r3016 r3025 18 18 /// </summary> 19 19 [AttributeUsage(AttributeTargets.Constructor, Inherited = false, AllowMultiple = false)] 20 public sealed class StorableConstructorAttribute : Attribute { 21 22 private static readonly BindingFlags allConstructors = 23 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; 24 25 private static Dictionary<Type, ConstructorInfo> constructorCache = 26 new Dictionary<Type, ConstructorInfo>(); 27 28 29 /// <summary> 30 /// Get a designated storable constructor for a type or <c>null</c>. 31 /// </summary> 32 /// <param name="type">The type.</param> 33 /// <returns>The <see cref="ConstructorInfo"/> of the storable constructor or <c>null</c></returns> 34 public static ConstructorInfo GetStorableConstructor(Type type) { 35 lock (constructorCache) { 36 if (constructorCache.ContainsKey(type)) 37 return constructorCache[type]; 38 foreach (ConstructorInfo ci in type.GetConstructors(allConstructors)) { 39 if (ci.GetCustomAttributes(typeof(StorableConstructorAttribute), false).Length > 0) { 40 if (ci.GetParameters().Length != 1 || 41 ci.GetParameters()[0].ParameterType != typeof(bool)) 42 throw new PersistenceException("StorableConstructor must have exactly one argument of type bool"); 43 constructorCache[type] = ci; 44 return ci; 45 } 46 } 47 constructorCache[type] = null; 48 return null; 49 } 50 } 51 } 20 public sealed class StorableConstructorAttribute : Attribute { } 52 21 } -
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.