using System.Collections.Generic; using System; using HeuristicLab.Persistence.Interfaces; namespace HeuristicLab.Persistence.Core { public struct ParentReference {} class CompositeObject { public object Obj { get; private set; } public List customValues; public CompositeObject(object obj) { Obj = obj; customValues = new List(); } public void AddValue(string name, object value, List finalFixes) { Tag t = new Tag(name, value) {finalFixes = finalFixes}; customValues.Add(t); } public Setter GetSetterForLastAddedValue(string name) { Tag t = customValues[customValues.Count - 1]; return value => t.Value = value; } } public delegate void Thunk(); public class DeSerializer { private readonly Dictionary id2obj; private readonly Dictionary serializerMapping; private readonly Stack parentStack; private readonly Dictionary typeIds; private List finalFixes; public DeSerializer( IEnumerable typeCache) { id2obj = new Dictionary(); parentStack = new Stack(); typeIds = new Dictionary(); serializerMapping = createSerializers(typeCache); } private Dictionary createSerializers(IEnumerable typeCache) { var map = new Dictionary(); foreach (var typeMapping in typeCache) { Type type = Type.GetType(typeMapping.TypeName, true); typeIds.Add(typeMapping.Id, type); if (typeMapping.Serializer != null) { Type serializerType = Type.GetType(typeMapping.Serializer); map.Add(type, Activator.CreateInstance(serializerType, true)); } } return map; } public object DeSerialize(IEnumerable tokens) { finalFixes = new List(); foreach (ISerializationToken token in tokens) { Type t = token.GetType(); if ( t == typeof(BeginToken) ) { CompositeStartHandler((BeginToken)token); } else if ( t == typeof(EndToken) ) { CompositeEndHandler((EndToken) token); } else if ( t == typeof(PrimitiveToken) ) { PrimitiveHandler((PrimitiveToken) token); } else if ( t == typeof(ReferenceToken) ) { ReferenceHandler((ReferenceToken) token); } else if (t == typeof(NullReferenceToken)) { NullHandler((NullReferenceToken)token); } else { throw new ApplicationException("invalid token type"); } } foreach (Thunk fix in finalFixes) { fix(); } return parentStack.Pop().Obj; } private void CompositeStartHandler(BeginToken token) { Type type = typeIds[(int)token.TypeId]; IDecomposer decomposer = null; if ( serializerMapping.ContainsKey(type) ) decomposer = serializerMapping[type] as IDecomposer; if (decomposer == null) throw new ApplicationException(String.Format( "No suitable method for deserialization of type \"{0}\" found.", type.VersionInvariantName())); object instance = decomposer.CreateInstance(type) ?? new ParentReference(); parentStack.Push(new CompositeObject(instance)); if ( token.Id != null ) id2obj.Add((int)token.Id, instance); } private void CompositeEndHandler(EndToken token) { Type type = typeIds[(int)token.TypeId]; IDecomposer decomposer = null; if (serializerMapping.ContainsKey(type)) decomposer = serializerMapping[type] as IDecomposer; if (decomposer == null) throw new ApplicationException(String.Format( "No suitable method for deserialization of type \"{0}\" found.", type.VersionInvariantName())); CompositeObject customComposite = parentStack.Pop(); object deserializedObject = decomposer.Populate(customComposite.Obj, customComposite.customValues, type); if ( token.Id != null ) id2obj[(int)token.Id] = deserializedObject; SetValue(token.Name, deserializedObject); } private void PrimitiveHandler(PrimitiveToken token) { Type type = typeIds[(int)token.TypeId]; object value = ((IFormatter) serializerMapping[type]).Parse(token.SerialData); if ( token.Id != null ) id2obj[(int)token.Id] = value; SetValue(token.Name, value); } private void ReferenceHandler(ReferenceToken token) { object referredObject = id2obj[token.Id]; SetValue(token.Name, referredObject); if (referredObject is ParentReference) { Setter set = parentStack.Peek().GetSetterForLastAddedValue(token.Name); finalFixes.Add(() => set(id2obj[token.Id])); } } private void NullHandler(NullReferenceToken token) { SetValue(token.Name, null); } private void SetValue(string name, object value) { if (parentStack.Count == 0) { parentStack.Push(new CompositeObject(value)); } else { parentStack.Peek().AddValue(name, value, finalFixes); } } } }