Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 13326 was 13326, checked in by swagner, 7 years ago

#2520: Created plugin for new persistence implementation

File size: 6.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 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 StorableClassAttribute StorableClassAttribute { 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      StorableClassAttribute = StorableClassAttribute.GetStorableClassAttribute(type);
60      if (StorableClassAttribute != 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          var fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic).
75                           Where(x => StorableAttribute.IsStorable(x));
76          foreach (var field in fieldInfos) {
77            var attrib = StorableAttribute.GetStorableAttribute(field);
78            var name = string.IsNullOrEmpty(attrib.Name) ? field.Name : attrib.Name;
79            fields.Add(new ComponentInfo(name, field, attrib, true, true));
80          }
81
82          var propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic).
83                      Where(x => x.GetIndexParameters().Length == 0).  // exclude indexed properties
84                      Where(x => StorableAttribute.IsStorable(x));
85          foreach (var property in propertyInfos) {
86            var attrib = StorableAttribute.GetStorableAttribute(property);
87            var name = string.IsNullOrEmpty(attrib.Name) ? property.Name : attrib.Name;
88            properties.Add(new ComponentInfo(name, property, attrib, property.CanRead, property.CanWrite));
89          }
90
91          var methodInfos = type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic).
92                            Where(x => StorableHookAttribute.IsStorableHook(x)).
93                            Where(x => (x.ReturnType == typeof(void)) && (x.GetParameters().Length == 0));
94          foreach (var method in methodInfos) {
95            foreach (var attrib in StorableHookAttribute.GetStorableHookAttributes(method)) {
96              if (attrib.HookType == HookType.BeforeSerialization)
97                beforeSerializationHooks.Add(method);
98              if (attrib.HookType == HookType.AfterDeserialization)
99                afterDeserializationHooks.Add(method);
100            }
101          }
102        }
103        Fields = fields;
104        Properties = properties;
105        BeforeSerializationHooks = beforeSerializationHooks;
106        AfterDeserializationHooks = afterDeserializationHooks;
107      }
108    }
109
110    public Func<object> GetConstructor() {
111      if (constructor != null) return constructor;
112
113      // get storable constructor
114      var ctor = Type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
115                     .Where(x => StorableConstructorAttribute.IsStorableConstructor(x))
116                     .Where(x => (x.GetParameters().Length == 1) && (x.GetParameters()[0].ParameterType == typeof(bool)))
117                     .FirstOrDefault();
118      if (ctor != null) {
119        DynamicMethod dm = new DynamicMethod("", typeof(object), null, Type, true);
120        ILGenerator ilgen = dm.GetILGenerator();
121        ilgen.Emit(OpCodes.Ldc_I4_1); // load true
122        ilgen.Emit(OpCodes.Newobj, ctor);
123        ilgen.Emit(OpCodes.Ret);
124        constructor = (Func<object>)dm.CreateDelegate(typeof(Func<object>));
125        return constructor;
126      }
127
128      // get default constructor
129      ctor = Type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
130                                 null, Type.EmptyTypes, null);
131      if (ctor != null) {
132        DynamicMethod dm = new DynamicMethod("", typeof(object), null, Type, true);
133        ILGenerator ilgen = dm.GetILGenerator();
134        ilgen.Emit(OpCodes.Newobj, ctor);
135        ilgen.Emit(OpCodes.Ret);
136        constructor = (Func<object>)dm.CreateDelegate(typeof(Func<object>));
137        return constructor;
138      }
139
140      throw new Exception("No storable constructor or parameterless constructor found.");
141    }
142  }
143}
Note: See TracBrowser for help on using the repository browser.