Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 15529 was 15529, checked in by jkarder, 6 years ago

#2520: worked on new persistence

  • changed message definitions
  • updated transformers
  • worked on conversions
  • cleaned up
File size: 7.8 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        string guidPrefix = StorableTypeAttribute.Guid.ToString().ToUpper();
61        // check constructors
62        if (!type.IsValueType && !type.IsEnum && !type.IsInterface &&
63          GetStorableConstructor() == null && GetDefaultConstructor() == null)
64          throw new PersistenceException("No storable constructor or parameterless constructor found.");
65
66        var fields = new List<ComponentInfo>();
67        var properties = new List<ComponentInfo>();
68        var beforeSerializationHooks = new List<MethodInfo>();
69        var afterDeserializationHooks = new List<MethodInfo>();
70
71        if (StorableTypeAttribute.MemberSelection != StorableMemberSelection.AllProperties) {
72          var fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic)
73                               .Where(x => !x.Name.StartsWith("<") && !x.Name.EndsWith("k__BackingField")); // exclude backing fields
74
75          if (StorableTypeAttribute.MemberSelection == StorableMemberSelection.MarkedOnly)
76            fieldInfos = fieldInfos.Where(StorableAttribute.IsStorable).ToArray();
77
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(name, guidPrefix + "." + 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().Any());  // exclude indexed properties
88
89          if (StorableTypeAttribute.MemberSelection == StorableMemberSelection.MarkedOnly)
90            propertyInfos = propertyInfos.Where(StorableAttribute.IsStorable).ToArray();
91
92          foreach (var property in propertyInfos) {
93            var attrib = StorableAttribute.GetStorableAttribute(property);
94            if ((!property.CanRead || !property.CanWrite) && (attrib == null || !attrib.AllowOneWay))
95              throw new PersistenceException("Properties must be readable and writable or have one way serialization explicitly enabled.");
96
97            var name = attrib == null || string.IsNullOrEmpty(attrib.Name) ? property.Name : attrib.Name;
98            properties.Add(new ComponentInfo(name, guidPrefix + "." + name, property, attrib, property.CanRead, property.CanWrite));
99          }
100        }
101
102        var methodInfos = type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic)
103                              .Where(StorableHookAttribute.IsStorableHook)
104                              .Where(x => x.ReturnType == typeof(void) && !x.GetParameters().Any());
105
106        foreach (var method in methodInfos) {
107          foreach (var attrib in StorableHookAttribute.GetStorableHookAttributes(method)) {
108            if (attrib.HookType == HookType.BeforeSerialization)
109              beforeSerializationHooks.Add(method);
110            if (attrib.HookType == HookType.AfterDeserialization)
111              afterDeserializationHooks.Add(method);
112          }
113        }
114
115        Fields = fields;
116        Properties = properties;
117        BeforeSerializationHooks = beforeSerializationHooks;
118        AfterDeserializationHooks = afterDeserializationHooks;
119      }
120    }
121
122    public Func<object> GetConstructor() {
123      if (constructor != null) return constructor;
124
125      // get storable constructor
126      var ctor = GetStorableConstructor();
127      if (ctor != null) {
128        DynamicMethod dm = new DynamicMethod("", typeof(object), null, Type, true);
129        ILGenerator ilgen = dm.GetILGenerator();
130        var local = ilgen.DeclareLocal(typeof(StorableConstructorFlag));
131        ilgen.Emit(OpCodes.Ldloca_S, local);
132        ilgen.Emit(OpCodes.Initobj, typeof(StorableConstructorFlag)); // load default value for StorableConstructorFlag
133        ilgen.Emit(OpCodes.Ldloc_0);
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      // get default constructor
141      ctor = GetDefaultConstructor();
142      if (ctor != null) {
143        DynamicMethod dm = new DynamicMethod("", typeof(object), null, Type, true);
144        ILGenerator ilgen = dm.GetILGenerator();
145        ilgen.Emit(OpCodes.Newobj, ctor);
146        ilgen.Emit(OpCodes.Ret);
147        constructor = (Func<object>)dm.CreateDelegate(typeof(Func<object>));
148        return constructor;
149      }
150
151      throw new PersistenceException("No storable constructor or parameterless constructor found.");
152    }
153
154    private ConstructorInfo GetStorableConstructor() {
155      return (from ctor in Type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
156              let parameters = ctor.GetParameters()
157              where StorableConstructorAttribute.IsStorableConstructor(ctor)
158                 && parameters.Length == 1
159                 && parameters[0].ParameterType == typeof(StorableConstructorFlag)
160              select ctor).FirstOrDefault();
161    }
162
163    private ConstructorInfo GetDefaultConstructor() {
164      return Type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
165    }
166  }
167}
Note: See TracBrowser for help on using the repository browser.