Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceOverhaul/HeuristicLab.Persistence/4.0/Core/TypeInfo.cs

Last change on this file was 14711, checked in by gkronber, 7 years ago

#2520

  • renamed StorableClass -> StorableType
  • changed persistence to use GUIDs instead of type names
File size: 7.1 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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 System.Reflection.Emit;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28
29namespace HeuristicLab.Persistence {
30  public sealed class TypeInfo {
31    private Func<object> constructor;
32
33    public Type Type { get; private set; }
34    public ITransformer Transformer { get; private set; }
35    public StorableTypeAttribute StorableTypeAttribute { get; private set; }
36    public IEnumerable<ComponentInfo> Fields { get; private set; }
37    public IEnumerable<ComponentInfo> Properties { get; private set; }
38    public IEnumerable<MethodInfo> BeforeSerializationHooks { get; private set; }
39    public IEnumerable<MethodInfo> AfterDeserializationHooks { get; private set; }
40    public long Used { get; set; }
41
42    public TypeInfo(Type type) {
43      constructor = null;
44      Type = type;
45      Fields = Enumerable.Empty<ComponentInfo>();
46      Properties = Enumerable.Empty<ComponentInfo>();
47      BeforeSerializationHooks = Enumerable.Empty<MethodInfo>();
48      AfterDeserializationHooks = Enumerable.Empty<MethodInfo>();
49      Used = 0;
50      Reflect();
51    }
52    public TypeInfo(Type type, ITransformer transformer)
53      : this(type) {
54      Transformer = transformer;
55    }
56
57    private void Reflect() {
58      var type = Type;
59      StorableTypeAttribute = StorableTypeAttribute.GetStorableTypeAttribute(type);
60      if (StorableTypeAttribute != null) {
61        // traverse type hierarchy from base type to sub types
62        Stack<Type> types = new Stack<Type>();
63        while (type != null) {
64          types.Push(type);
65          type = type.BaseType;
66        }
67
68        var fields = new List<ComponentInfo>();
69        var properties = new List<ComponentInfo>();
70        var beforeSerializationHooks = new List<MethodInfo>();
71        var afterDeserializationHooks = new List<MethodInfo>();
72        while (types.Count > 0) {
73          type = types.Pop();
74          if (StorableTypeAttribute.MemberSelection != StorableMemberSelection.AllProperties) {
75            var fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic)
76                                 .Where(x => !x.Name.StartsWith("<") && !x.Name.EndsWith("k__BackingField")); // exclude backing fields
77            if (StorableTypeAttribute.MemberSelection == StorableMemberSelection.MarkedOnly)
78              fieldInfos = fieldInfos.Where(x => StorableAttribute.IsStorable(x)).ToArray();
79            foreach (var field in fieldInfos) {
80              var attrib = StorableAttribute.GetStorableAttribute(field);
81              var name = attrib == null || string.IsNullOrEmpty(attrib.Name) ? field.Name : attrib.Name;
82              fields.Add(new ComponentInfo(type.Name + '.' + name, field, attrib, true, true));
83            }
84          }
85
86          if (StorableTypeAttribute.MemberSelection != StorableMemberSelection.AllFields) {
87            var propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic).
88                        Where(x => x.GetIndexParameters().Length == 0);  // exclude indexed properties
89            if (StorableTypeAttribute.MemberSelection == StorableMemberSelection.MarkedOnly)
90              propertyInfos = propertyInfos.Where(x => StorableAttribute.IsStorable(x)).ToArray();
91            foreach (var property in propertyInfos) {
92              var attrib = StorableAttribute.GetStorableAttribute(property);
93              var name = attrib == null || string.IsNullOrEmpty(attrib.Name) ? property.Name : attrib.Name;
94              properties.Add(new ComponentInfo(type.Name + '.' + name, property, attrib, property.CanRead, property.CanWrite));
95            }
96          }
97
98          var methodInfos = type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic).
99                            Where(x => StorableHookAttribute.IsStorableHook(x)).
100                            Where(x => (x.ReturnType == typeof(void)) && (x.GetParameters().Length == 0));
101          foreach (var method in methodInfos) {
102            foreach (var attrib in StorableHookAttribute.GetStorableHookAttributes(method)) {
103              if (attrib.HookType == HookType.BeforeSerialization)
104                beforeSerializationHooks.Add(method);
105              if (attrib.HookType == HookType.AfterDeserialization)
106                afterDeserializationHooks.Add(method);
107            }
108          }
109        }
110        Fields = fields;
111        Properties = properties;
112        BeforeSerializationHooks = beforeSerializationHooks;
113        AfterDeserializationHooks = afterDeserializationHooks;
114      }
115    }
116
117    public Func<object> GetConstructor() {
118      if (constructor != null) return constructor;
119
120      // get storable constructor
121      var ctor = Type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
122                     .Where(x => StorableConstructorAttribute.IsStorableConstructor(x))
123                     .Where(x => (x.GetParameters().Length == 1) && (x.GetParameters()[0].ParameterType == typeof(bool)))
124                     .FirstOrDefault();
125      if (ctor != null) {
126        DynamicMethod dm = new DynamicMethod("", typeof(object), null, Type, true);
127        ILGenerator ilgen = dm.GetILGenerator();
128        ilgen.Emit(OpCodes.Ldc_I4_1); // load true
129        ilgen.Emit(OpCodes.Newobj, ctor);
130        ilgen.Emit(OpCodes.Ret);
131        constructor = (Func<object>)dm.CreateDelegate(typeof(Func<object>));
132        return constructor;
133      }
134
135      // get default constructor
136      ctor = Type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
137                                 null, Type.EmptyTypes, null);
138      if (ctor != null) {
139        DynamicMethod dm = new DynamicMethod("", typeof(object), null, Type, true);
140        ILGenerator ilgen = dm.GetILGenerator();
141        ilgen.Emit(OpCodes.Newobj, ctor);
142        ilgen.Emit(OpCodes.Ret);
143        constructor = (Func<object>)dm.CreateDelegate(typeof(Func<object>));
144        return constructor;
145      }
146
147      throw new Exception("No storable constructor or parameterless constructor found.");
148    }
149  }
150}
Note: See TracBrowser for help on using the repository browser.