Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableAttribute.cs @ 1938

Last change on this file since 1938 was 1938, checked in by epitzer, 15 years ago

Resolve name clashes of overridden and shadowed properties (#659)

File size: 6.2 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Reflection;
4using System.Text;
5
6namespace HeuristicLab.Persistence.Default.CompositeSerializers.Storable {
7
8  [AttributeUsage(
9    AttributeTargets.Field | AttributeTargets.Property,
10    AllowMultiple = false,
11    Inherited = false)]
12  public class StorableAttribute : Attribute {
13
14    public string Name { get; set; }
15    public object DefaultValue { get; set; }
16
17    public override string ToString() {
18      StringBuilder sb = new StringBuilder();
19      sb.Append("[Storable");
20      if (Name != null || DefaultValue != null)
21        sb.Append('(');
22      if (Name != null) {
23        sb.Append("Name = \"").Append(Name).Append("\"");
24        if (DefaultValue != null)
25          sb.Append(", ");
26      }
27      if (DefaultValue != null)
28        sb.Append("DefaultValue = \"").Append(DefaultValue).Append("\"");
29      if (Name != null || DefaultValue != null)
30        sb.Append(')');
31      sb.Append(']');
32      return sb.ToString();
33    }
34
35    private const BindingFlags instanceMembers =
36      BindingFlags.Instance |
37      BindingFlags.Public |
38      BindingFlags.NonPublic |
39      BindingFlags.DeclaredOnly;
40
41    public sealed class StorableMemberInfo {
42      public StorableAttribute Attribute { get; private set; }
43      public MemberInfo MemberInfo { get; private set; }
44      public StorableMemberInfo(StorableAttribute attribute, MemberInfo memberInfo) {
45        this.Attribute = attribute;
46        this.MemberInfo = memberInfo;
47      }
48      public override string ToString() {
49        return new StringBuilder()
50          .Append('[').Append(Attribute).Append(", ")
51          .Append(MemberInfo).Append('}').ToString();
52      }
53    }
54
55    sealed class TypeQuery {
56      public Type Type { get; private set; }
57      public bool Inherited { get; private set; }
58      public TypeQuery(Type type, bool inherited) {
59        this.Type = type;
60        this.Inherited = inherited;
61      }
62    }
63
64    sealed class MemberCache : Dictionary<TypeQuery, IEnumerable<StorableMemberInfo>> { }
65
66    private static MemberCache memberCache = new MemberCache();
67
68    public static IEnumerable<StorableMemberInfo> GetStorableMembers(Type type) {
69      return GetStorableMembers(type, true);
70    }
71
72    public static IEnumerable<StorableMemberInfo> GetStorableMembers(Type type, bool inherited) {
73      var query = new TypeQuery(type, inherited);
74      if (memberCache.ContainsKey(query))
75        return memberCache[query];
76      var storablesMembers = GenerateStorableMembers(type, inherited);
77      memberCache[query] = storablesMembers;
78      return storablesMembers;
79    }
80
81    private static IEnumerable<StorableMemberInfo> GenerateStorableMembers(Type type, bool inherited) {
82      var storableMembers = new List<StorableMemberInfo>();
83      if (inherited && type.BaseType != null)
84        storableMembers.AddRange(GenerateStorableMembers(type.BaseType, true));
85      foreach (MemberInfo memberInfo in type.GetMembers(instanceMembers)) {
86        foreach (object attribute in memberInfo.GetCustomAttributes(false)) {
87          StorableAttribute storableAttribute = attribute as StorableAttribute;
88          if (storableAttribute != null) {
89            storableMembers.Add(new StorableMemberInfo(storableAttribute, memberInfo));
90          }
91        }
92      }
93      return storableMembers;
94    }
95
96    public static Dictionary<string, DataMemberAccessor> GetStorableAccessors(object obj) {
97      var storableAccessors = new Dictionary<string, DataMemberAccessor>();
98      var nameMapping = createNameMapping(obj.GetType());
99      var finalNameMapping = analyzeNameMapping(nameMapping);
100      foreach (var mapping in finalNameMapping) {
101        storableAccessors.Add(mapping.Value.Attribute.Name ?? mapping.Key,
102          new DataMemberAccessor(
103            mapping.Value.MemberInfo,
104            mapping.Value.Attribute.Name ?? mapping.Key,
105            mapping.Value.Attribute.DefaultValue,
106            obj));
107      }
108      return storableAccessors;
109    }
110
111    private static Dictionary<string, StorableMemberInfo> analyzeNameMapping(
112        Dictionary<string, List<StorableMemberInfo>> nameMapping) {
113      var finalNameMapping = new Dictionary<string, StorableMemberInfo>();
114      foreach (var attributes in nameMapping) {
115        if (attributes.Value.Count == 1) {
116          finalNameMapping[attributes.Key] = attributes.Value[0];
117        } else if (attributes.Value[0].MemberInfo.MemberType == MemberTypes.Field) {
118          foreach (var attribute in attributes.Value) {
119            StringBuilder sb = new StringBuilder();
120            sb.Append(attribute.MemberInfo.ReflectedType.FullName).Append('.')
121              .Append(attribute.MemberInfo.Name);
122            finalNameMapping[sb.ToString()] = attribute;
123          }
124        } else {
125          var uniqueAccessors = new Dictionary<Type, StorableMemberInfo>();
126          foreach (var attribute in attributes.Value) {
127            uniqueAccessors[((PropertyInfo)attribute.MemberInfo).GetGetMethod(true).GetBaseDefinition().DeclaringType] =
128              attribute;
129          }
130          if (uniqueAccessors.Count == 1) {
131            var it = uniqueAccessors.Values.GetEnumerator();
132            it.MoveNext();
133            finalNameMapping[attributes.Key] = it.Current;
134          } else {
135            foreach (var attribute in uniqueAccessors.Values) {
136              StringBuilder sb = new StringBuilder();
137              sb.Append(attribute.MemberInfo.DeclaringType.FullName).Append('.')
138                .Append(attribute.MemberInfo.Name);
139              finalNameMapping[sb.ToString()] = attribute;
140            }
141          }
142        }
143      }
144      return finalNameMapping;
145    }
146
147    private static Dictionary<string, List<StorableMemberInfo>> createNameMapping(Type type) {
148      var nameMapping = new Dictionary<string, List<StorableMemberInfo>>();
149      foreach (StorableMemberInfo storable in GetStorableMembers(type)) {
150        if (!nameMapping.ContainsKey(storable.MemberInfo.Name))
151          nameMapping[storable.MemberInfo.Name] = new List<StorableMemberInfo>();
152        nameMapping[storable.MemberInfo.Name].Add(storable);
153      }
154      return nameMapping;
155    }
156  }
157}
Note: See TracBrowser for help on using the repository browser.