1 | using System;
|
---|
2 | using System.Collections.Generic;
|
---|
3 | using System.Reflection;
|
---|
4 | using System.Text;
|
---|
5 |
|
---|
6 | namespace 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 | }
|
---|