Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceReintegration/HeuristicLab.Persistence/4.0/Core/TypeInfo.cs @ 15018

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

#2520 introduced StorableConstructorFlag type for StorableConstructors

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