#region License Information /* HeuristicLab * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; namespace HeuristicLab.Persistence { public sealed class TypeInfo { private Func constructor; public Type Type { get; private set; } public ITransformer Transformer { get; private set; } public StorableTypeAttribute StorableTypeAttribute { get; private set; } public IEnumerable Fields { get; private set; } public IEnumerable Properties { get; private set; } public IEnumerable BeforeSerializationHooks { get; private set; } public IEnumerable AfterDeserializationHooks { get; private set; } public long Used { get; set; } public TypeInfo(Type type) { constructor = null; Type = type; Fields = Enumerable.Empty(); Properties = Enumerable.Empty(); BeforeSerializationHooks = Enumerable.Empty(); AfterDeserializationHooks = Enumerable.Empty(); Used = 0; Reflect(); } public TypeInfo(Type type, ITransformer transformer) : this(type) { Transformer = transformer; } private void Reflect() { var type = Type; StorableTypeAttribute = StorableTypeAttribute.GetStorableTypeAttribute(type); if (StorableTypeAttribute != null) { // traverse type hierarchy from base type to sub types Stack types = new Stack(); while (type != null) { types.Push(type); type = type.BaseType; } var fields = new List(); var properties = new List(); var beforeSerializationHooks = new List(); var afterDeserializationHooks = new List(); while (types.Count > 0) { type = types.Pop(); if (StorableTypeAttribute.MemberSelection != StorableMemberSelection.AllProperties) { var fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic) .Where(x => !x.Name.StartsWith("<") && !x.Name.EndsWith("k__BackingField")); // exclude backing fields if (StorableTypeAttribute.MemberSelection == StorableMemberSelection.MarkedOnly) fieldInfos = fieldInfos.Where(x => StorableAttribute.IsStorable(x)).ToArray(); foreach (var field in fieldInfos) { var attrib = StorableAttribute.GetStorableAttribute(field); var name = attrib == null || string.IsNullOrEmpty(attrib.Name) ? field.Name : attrib.Name; fields.Add(new ComponentInfo(type.Name + '.' + name, field, attrib, true, true)); } } if (StorableTypeAttribute.MemberSelection != StorableMemberSelection.AllFields) { var propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic). Where(x => x.GetIndexParameters().Length == 0); // exclude indexed properties if (StorableTypeAttribute.MemberSelection == StorableMemberSelection.MarkedOnly) propertyInfos = propertyInfos.Where(x => StorableAttribute.IsStorable(x)).ToArray(); foreach (var property in propertyInfos) { var attrib = StorableAttribute.GetStorableAttribute(property); var name = attrib == null || string.IsNullOrEmpty(attrib.Name) ? property.Name : attrib.Name; properties.Add(new ComponentInfo(type.Name + '.' + name, property, attrib, property.CanRead, property.CanWrite)); } } var methodInfos = type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic). Where(x => StorableHookAttribute.IsStorableHook(x)). Where(x => (x.ReturnType == typeof(void)) && (x.GetParameters().Length == 0)); foreach (var method in methodInfos) { foreach (var attrib in StorableHookAttribute.GetStorableHookAttributes(method)) { if (attrib.HookType == HookType.BeforeSerialization) beforeSerializationHooks.Add(method); if (attrib.HookType == HookType.AfterDeserialization) afterDeserializationHooks.Add(method); } } } Fields = fields; Properties = properties; BeforeSerializationHooks = beforeSerializationHooks; AfterDeserializationHooks = afterDeserializationHooks; } } public Func GetConstructor() { if (constructor != null) return constructor; // get storable constructor var ctor = Type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(x => StorableConstructorAttribute.IsStorableConstructor(x)) .Where(x => (x.GetParameters().Length == 1) && (x.GetParameters()[0].ParameterType == typeof(bool))) .FirstOrDefault(); if (ctor != null) { DynamicMethod dm = new DynamicMethod("", typeof(object), null, Type, true); ILGenerator ilgen = dm.GetILGenerator(); ilgen.Emit(OpCodes.Ldc_I4_1); // load true ilgen.Emit(OpCodes.Newobj, ctor); ilgen.Emit(OpCodes.Ret); constructor = (Func)dm.CreateDelegate(typeof(Func)); return constructor; } // get default constructor ctor = Type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (ctor != null) { DynamicMethod dm = new DynamicMethod("", typeof(object), null, Type, true); ILGenerator ilgen = dm.GetILGenerator(); ilgen.Emit(OpCodes.Newobj, ctor); ilgen.Emit(OpCodes.Ret); constructor = (Func)dm.CreateDelegate(typeof(Func)); return constructor; } throw new Exception("No storable constructor or parameterless constructor found."); } } }