using System.Collections.Generic; using System; using HeuristicLab.Persistence.Interfaces; namespace HeuristicLab.Persistence.Core { struct ParentReference { } delegate void Setter(object value); interface IAccessibleObject { object Obj { get; } Setter GetSetter(string name); } class CustomComposite : IAccessibleObject { public object Obj { get; private set; } public readonly List customValues; public CustomComposite(object obj) { Obj = obj; customValues = new List(); } public void AddValue(object value) { customValues.Add(value); } public Setter GetSetter(string name) { int index = customValues.Count - 1; return value => customValues[index] = value; } } class StorableComposite : IAccessibleObject { public object Obj { get; private set; } public readonly Dictionary accessorDict; public StorableComposite(object obj, Dictionary accessorDict) { Obj = obj; this.accessorDict = new Dictionary(); foreach (KeyValuePair pair in accessorDict) { this.accessorDict.Add( pair.Value.Name, pair.Value); } } public void SetValue(string name, object value) { accessorDict[name].Set(value); accessorDict.Remove(name); } public Setter GetSetter(string name) { return value => accessorDict[name].Set(value); } public void PopulateDefaultValues() { foreach (var pair in accessorDict) { pair.Value.Set(pair.Value.DefaultValue); } } } public class DeSerializer { private delegate void Handler(ISerializationToken token); private delegate void Thunk(); private readonly Dictionary id2obj; private readonly Dictionary handlers; private readonly Stack parentStack; private readonly Configuration configuration; private readonly Dictionary typeIds; private List finalFixes; public DeSerializer( IEnumerable> typeCache, Configuration configuration) { this.configuration = configuration; id2obj = new Dictionary(); parentStack = new Stack(); handlers = new Dictionary { {typeof (BeginToken), CompositeStartHandler}, {typeof (EndToken), CompositeEndHandler}, {typeof (PrimitiveToken), PrimitiveHandler}, {typeof (ReferenceToken), ReferenceHandler}, {typeof (NullReferenceToken), NullHandler} }; typeIds = new Dictionary(); foreach ( var pair in typeCache ) { Type type = Type.GetType(pair.Key); typeIds.Add(pair.Value, type); } } public object DeSerialize(IEnumerable tokens) { finalFixes = new List(); foreach (ISerializationToken token in tokens) { handlers[token.GetType()].Invoke(token); } foreach (Thunk fix in finalFixes) { fix(); } return parentStack.Pop().Obj; } private void CompositeStartHandler(ISerializationToken token) { BeginToken start = (BeginToken)token; object instance; Type type = typeIds[(int)start.TypeId]; if (configuration.GetDecomposer(type) != null) { instance = new ParentReference(); parentStack.Push(new CustomComposite(instance)); } else { instance = Activator.CreateInstance(type, true); Dictionary accessorDict = StorableAttribute.GetAutostorableAccessors(instance); parentStack.Push(new StorableComposite(instance, accessorDict)); } if ( start.Id != null ) id2obj.Add((int)start.Id, instance); } private void CompositeEndHandler(ISerializationToken token) { EndToken end = (EndToken)token; Type type = typeIds[(int)end.TypeId]; IDecomposer decomposer = configuration.GetDecomposer(type); if (decomposer != null) { CustomComposite customComposite = (CustomComposite)parentStack.Pop(); object deserializedObject = decomposer.Compose(customComposite.customValues, type); if ( end.Id != null ) id2obj[(int)end.Id] = deserializedObject; SetValue(end.Name, deserializedObject); } else { StorableComposite storableComposite = (StorableComposite)parentStack.Pop(); storableComposite.PopulateDefaultValues(); SetValue(end.Name, storableComposite.Obj); } } private void PrimitiveHandler(ISerializationToken token) { PrimitiveToken primitive = (PrimitiveToken)token; Type type = typeIds[(int)primitive.TypeId]; object value = configuration .GetFormatter(type) .Parse(primitive.SerialData); if ( ! value.GetType().IsValueType ) id2obj[(int)primitive.Id] = value; SetValue(primitive.Name, value); } private void ReferenceHandler(ISerializationToken token) { ReferenceToken reference = (ReferenceToken)token; object referredObject = id2obj[reference.Id]; SetValue(reference.Name, id2obj[reference.Id]); if (referredObject is ParentReference) { Setter set = parentStack.Peek().GetSetter(reference.Name); int id = reference.Id; finalFixes.Add(() => set(id2obj[id])); } } private void NullHandler(ISerializationToken token) { NullReferenceToken nil = (NullReferenceToken)token; SetValue(nil.Name, null); } private void SetValue(string name, object value) { if (parentStack.Count == 0) { parentStack.Push(new StorableComposite(value, new Dictionary())); } else { object accessibleObject = parentStack.Peek(); if (accessibleObject is StorableComposite) { ((StorableComposite)accessibleObject).SetValue(name, value); } else if (accessibleObject is CustomComposite) { ((CustomComposite)accessibleObject).AddValue(value); } } } } }