#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;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Persistence {
public sealed class TypeInfo {
private Func constructor;
public Type Type { get; private set; }
public ITransformer Transformer { get; private set; }
public StorableClassAttribute StorableClassAttribute { 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;
StorableClassAttribute = StorableClassAttribute.GetStorableClassAttribute(type);
if (StorableClassAttribute != 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 (StorableClassAttribute.Type != StorableClassType.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 (StorableClassAttribute.Type == StorableClassType.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 (StorableClassAttribute.Type != StorableClassType.AllFields) {
var propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic).
Where(x => x.GetIndexParameters().Length == 0); // exclude indexed properties
if (StorableClassAttribute.Type == StorableClassType.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.");
}
}
}