Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableReflection.cs @ 4695

Last change on this file since 4695 was 4068, checked in by swagner, 14 years ago

Sorted usings and removed unused usings in entire solution (#1094)

File size: 8.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using System.Reflection;
26using HeuristicLab.Persistence.Core;
27
28namespace HeuristicLab.Persistence.Default.CompositeSerializers.Storable {
29
30  internal static class StorableReflection {
31
32    private const BindingFlags DECLARED_INSTANCE_MEMBERS =
33      BindingFlags.Instance |
34      BindingFlags.Public |
35      BindingFlags.NonPublic |
36      BindingFlags.DeclaredOnly;
37
38    public delegate void Hook(object o);
39
40    public static IEnumerable<StorableMemberInfo> GenerateStorableMembers(Type type) {
41      var storableMembers = new List<StorableMemberInfo>();
42      if (type.BaseType != null)
43        storableMembers.AddRange(GenerateStorableMembers(type.BaseType));
44
45      var storableClassAttribute = GetStorableClassAttribute(type);
46      if (storableClassAttribute != null) {
47        switch (storableClassAttribute.Type) {
48          case StorableClassType.MarkedOnly:
49            AddMarkedMembers(type, storableMembers); break;
50          case StorableClassType.AllFields:
51            AddAll(type, MemberTypes.Field, storableMembers); break;
52          case StorableClassType.AllProperties:
53            AddAll(type, MemberTypes.Property, storableMembers); break;
54          case StorableClassType.AllFieldsAndAllProperties:
55            AddAll(type, MemberTypes.Field | MemberTypes.Property, storableMembers); break;
56          default:
57            throw new PersistenceException("unsupported [StorableClassType]: " + storableClassAttribute.Type);
58        }
59      }
60
61      return DisentangleNameMapping(storableMembers);
62    }
63
64    public static bool IsEmptyOrStorableType(Type type, bool recursive) {
65      if (!HasStorableClassAttribute(type) && !IsEmptyType(type, false)) return false;
66      return !recursive || type.BaseType == null || IsEmptyOrStorableType(type.BaseType, true);
67    }
68
69    private static object[] emptyArgs = new object[0];
70
71    public static IEnumerable<Hook> CollectHooks(HookType hookType, Type type) {
72      if (type.BaseType != null)
73        foreach (var hook in CollectHooks(hookType, type.BaseType))
74          yield return hook;
75      if (HasStorableClassAttribute(type)) {
76        foreach (MethodInfo methodInfo in type.GetMethods(DECLARED_INSTANCE_MEMBERS)) {
77          if (methodInfo.ReturnType == typeof(void) && methodInfo.GetParameters().Length == 0) {
78            foreach (StorableHookAttribute hook in methodInfo.GetCustomAttributes(typeof(StorableHookAttribute), false)) {
79              if (hook != null && hook.HookType == hookType) {
80                yield return CreateHook(methodInfo);
81              }
82            }
83          }
84        }
85      }
86    }
87
88    private static Hook CreateHook(MethodInfo methodInfo) {
89      return new Hook((o) => methodInfo.Invoke(o, emptyArgs));
90    }
91
92    #region [Storable] helpers
93
94    private static void AddMarkedMembers(Type type, List<StorableMemberInfo> storableMembers) {
95      foreach (MemberInfo memberInfo in type.GetMembers(DECLARED_INSTANCE_MEMBERS)) {
96        if (memberInfo.MemberType == MemberTypes.Field ||
97          memberInfo.MemberType == MemberTypes.Property) {
98          foreach (StorableAttribute attribute in memberInfo.GetCustomAttributes(typeof(StorableAttribute), false)) {
99            storableMembers.Add(new StorableMemberInfo(attribute, memberInfo));
100          }
101        }
102      }
103    }
104
105    private static void AddAll(Type type, MemberTypes memberTypes, List<StorableMemberInfo> storableMembers) {
106      foreach (MemberInfo memberInfo in type.GetMembers(DECLARED_INSTANCE_MEMBERS)) {
107        if ((memberInfo.MemberType & memberTypes) == memberInfo.MemberType &&
108            !memberInfo.Name.StartsWith("<") &&
109            !memberInfo.Name.EndsWith("k__BackingField"))
110          storableMembers.Add(new StorableMemberInfo(memberInfo));
111      }
112    }
113
114
115    private static IEnumerable<StorableMemberInfo> DisentangleNameMapping(
116        IEnumerable<StorableMemberInfo> storableMemberInfos) {
117      var nameGrouping = new Dictionary<string, List<StorableMemberInfo>>();
118      foreach (StorableMemberInfo storable in storableMemberInfos) {
119        if (!nameGrouping.ContainsKey(storable.MemberInfo.Name))
120          nameGrouping[storable.MemberInfo.Name] = new List<StorableMemberInfo>();
121        nameGrouping[storable.MemberInfo.Name].Add(storable);
122      }
123      var memberInfos = new List<StorableMemberInfo>();
124      foreach (var storableMemberInfoGroup in nameGrouping.Values) {
125        if (storableMemberInfoGroup.Count == 1) {
126          storableMemberInfoGroup[0].SetDisentangledName(storableMemberInfoGroup[0].MemberInfo.Name);
127          memberInfos.Add(storableMemberInfoGroup[0]);
128        } else if (storableMemberInfoGroup[0].MemberInfo.MemberType == MemberTypes.Field) {
129          foreach (var storableMemberInfo in storableMemberInfoGroup) {
130            storableMemberInfo.SetDisentangledName(storableMemberInfo.FullyQualifiedMemberName);
131            memberInfos.Add(storableMemberInfo);
132          }
133        } else {
134          memberInfos.AddRange(MergePropertyAccessors(storableMemberInfoGroup));
135        }
136      }
137      return memberInfos;
138    }
139
140    private static IEnumerable<StorableMemberInfo> MergePropertyAccessors(List<StorableMemberInfo> members) {
141      var uniqueAccessors = new Dictionary<Type, StorableMemberInfo>();
142      foreach (var member in members)
143        uniqueAccessors[member.GetPropertyDeclaringBaseType()] = member;
144      if (uniqueAccessors.Count == 1) {
145        var storableMemberInfo = uniqueAccessors.Values.First();
146        storableMemberInfo.SetDisentangledName(storableMemberInfo.MemberInfo.Name);
147        yield return storableMemberInfo;
148      } else {
149        foreach (var attribute in uniqueAccessors.Values) {
150          attribute.SetDisentangledName(attribute.FullyQualifiedMemberName);
151          yield return attribute;
152        }
153      }
154    }
155
156    #endregion
157
158    #region [StorableClass] helpers
159
160    private static StorableClassAttribute GetStorableClassAttribute(Type type) {
161      lock (storableClassCache) {
162        if (storableClassCache.ContainsKey(type))
163          return storableClassCache[type];
164        StorableClassAttribute attribute = type
165          .GetCustomAttributes(typeof(StorableClassAttribute), false)
166          .SingleOrDefault() as StorableClassAttribute;
167        storableClassCache.Add(type, attribute);
168        return attribute;
169      }
170    }
171
172    public static bool HasStorableClassAttribute(Type type) {
173      return GetStorableClassAttribute(type) != null;
174    }
175
176    private static Dictionary<Type, StorableClassAttribute> storableClassCache =
177      new Dictionary<Type, StorableClassAttribute>();
178
179    #endregion
180
181    #region other helpers
182
183    private static bool IsEmptyType(Type type, bool recursive) {
184      foreach (MemberInfo memberInfo in type.GetMembers(DECLARED_INSTANCE_MEMBERS)) {
185        if (IsModifiableMember(memberInfo)) return false;
186      }
187      return !recursive || type.BaseType == null || IsEmptyType(type.BaseType, true);
188    }
189
190    private static bool IsModifiableMember(MemberInfo memberInfo) {
191      return memberInfo.MemberType == MemberTypes.Field && IsModifiableField((FieldInfo)memberInfo) ||
192             memberInfo.MemberType == MemberTypes.Property && IsModifiableProperty((PropertyInfo)memberInfo);
193    }
194
195    private static bool IsModifiableField(FieldInfo fi) {
196      return !fi.IsLiteral && !fi.IsInitOnly;
197    }
198
199    private static bool IsModifiableProperty(PropertyInfo pi) {
200      return pi.CanWrite;
201    }
202
203    #endregion
204
205  }
206}
Note: See TracBrowser for help on using the repository browser.