Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceSpeedUp/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableClassAnalyzer.cs @ 6224

Last change on this file since 6224 was 6224, checked in by epitzer, 13 years ago

remove unused and unnecessary StorableClassType enum (#1530)

File size: 6.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 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;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable.Descriptors;
28
29namespace HeuristicLab.Persistence.Default.CompositeSerializers.Storable {
30
31  /// <summary>
32  /// Analyzes storables classes and creates a datastructure containing all required
33  /// reflection information to serialize and deserialized these types.
34  /// </summary> 
35  public static class StorableClassAnalyzer {
36
37    private static Dictionary<Type, TypeDescriptor> typeDescriptors = new Dictionary<Type, TypeDescriptor>();
38    private static object typeDescriptorLock = new object();
39
40    /// <summary>
41    /// A list of all types that have been analyzed by this instance.
42    /// </summary>
43    public static IEnumerable<Type> KnownTypes { get { lock (typeDescriptorLock) { return typeDescriptors.Keys; } } }
44
45    /// <summary>
46    /// Retrieve analyzis results for a certain type. This either returns
47    /// already cached results or analyzes the given type and caches the
48    /// results.
49    /// </summary>
50    /// <param name="type">The type to be analyzed.</param>
51    /// <returns>A TypeDescriptor object that encapsulates all necessary reflection information.</returns>
52    public static TypeDescriptor GetDescriptor(Type type) {
53      TypeDescriptor typeDescriptor = null;
54      lock (typeDescriptorLock) {
55        typeDescriptors.TryGetValue(type, out typeDescriptor);
56      }
57      if (typeDescriptor != null)
58        return typeDescriptor;
59      typeDescriptor = new TypeDescriptor(type);
60      AddMembers(type, typeDescriptor);
61      if (!typeDescriptor.IsInvalid) {
62        typeDescriptor.Disentangle();
63        lock (typeDescriptorLock) {
64          typeDescriptors[type] = typeDescriptor;
65        }
66      }
67      return typeDescriptor;
68    }
69
70    private static void AddMembers(Type type, TypeDescriptor typeDescriptor) {
71      if (type.BaseType != null) {
72        typeDescriptor.BaseTypeDescriptor = StorableClassAnalyzer.GetDescriptor(type.BaseType);
73        if (typeDescriptor.BaseTypeDescriptor.IsInvalid) {
74          typeDescriptor.IsInvalid = true;
75          return;
76        }
77      }
78      var attribute = (StorableClassAttribute)type.GetCustomAttributes(typeof(StorableClassAttribute), false).SingleOrDefault();
79      typeDescriptor.IsStorableClass = attribute != null;
80      foreach (MemberInfo member in type.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) {
81        switch (member.MemberType) {
82          case MemberTypes.Constructor: MaybeAddConstructor((ConstructorInfo)member, typeDescriptor); break;
83          case MemberTypes.Field: MaybeAddField((FieldInfo)member, typeDescriptor, attribute); break;
84          case MemberTypes.Property: MaybeAddProperty((PropertyInfo)member, typeDescriptor, attribute); break;
85          case MemberTypes.Method: MaybeAddHook((MethodInfo)member, typeDescriptor); break;
86        }
87        if (typeDescriptor.IsInvalid) return;
88      }
89    }
90
91    private static bool IsMutableField(FieldInfo fi) {
92      return !fi.IsLiteral && !fi.IsInitOnly;
93    }
94
95    private static bool IsMutableProperty(PropertyInfo pi) {
96      return pi.CanWrite;
97    }
98
99    private static void MaybeAddConstructor(ConstructorInfo constructorInfo, TypeDescriptor typeDescriptor) {
100      ParameterInfo[] parameters = constructorInfo.GetParameters();
101      if (parameters.Length == 0) {
102        typeDescriptor.HasDefaultConstructor = true;
103        typeDescriptor.DefaultConstructor = constructorInfo;
104      }
105      if (parameters.Length == 1 &&
106          parameters[0].ParameterType == typeof(bool) &&
107          constructorInfo.GetCustomAttributes(typeof(StorableConstructorAttribute), false).Length == 1) {
108        typeDescriptor.HasStorableConstructor = true;
109        typeDescriptor.StorableConstructor = constructorInfo;
110      }
111    }
112
113    private static void MaybeAddField(FieldInfo fieldInfo, TypeDescriptor typeDescriptor, StorableClassAttribute classAttribute) {
114      if (classAttribute == null) {
115        if (IsMutableField(fieldInfo)) typeDescriptor.IsInvalid = true;
116        return;
117      }
118      if (fieldInfo.Name.StartsWith("<") || fieldInfo.Name.EndsWith("k__BackingField"))
119        return;
120      var attribute = (StorableAttribute)fieldInfo.GetCustomAttributes(typeof(StorableAttribute), false).SingleOrDefault();
121      if (attribute != null)
122        typeDescriptor.Fields.Add(new FieldDescriptor(typeDescriptor, fieldInfo, attribute));
123    }
124
125    private static void MaybeAddProperty(PropertyInfo propertyInfo, TypeDescriptor typeDescriptor, StorableClassAttribute classAttribute) {
126      if (classAttribute == null) {
127        if (IsMutableProperty(propertyInfo)) typeDescriptor.IsInvalid = true;
128        return;
129      }
130      var attribute = (StorableAttribute)propertyInfo.GetCustomAttributes(typeof(StorableAttribute), false).SingleOrDefault();
131      if (attribute != null) {
132        if (!(attribute.AllowOneWay || propertyInfo.CanRead && propertyInfo.CanWrite))
133          throw new PersistenceException("Properties have to be read/write or marked as one way storable");
134        typeDescriptor.Properties.Add(new PropertyDescriptor(typeDescriptor, propertyInfo, attribute));
135      }
136    }
137
138    private static void MaybeAddHook(MethodInfo methodInfo, TypeDescriptor typeDescriptor) {
139      if (methodInfo.ReturnType != typeof(void) || methodInfo.GetParameters().Length > 0)
140        return;
141      var attribute = (StorableHookAttribute)methodInfo.GetCustomAttributes(typeof(StorableHookAttribute), false).SingleOrDefault();
142      if (attribute != null)
143        typeDescriptor.Hooks.Add(new HookDescriptor(typeDescriptor, methodInfo, attribute.HookType));
144    }
145  }
146}
Note: See TracBrowser for help on using the repository browser.