using System.Collections.Generic; using System; using HeuristicLab.Persistence.Interfaces; namespace HeuristicLab.Persistence { struct ParentReference { } delegate void Setter(object value); interface IAccessibleObject { object Obj { get; } Setter GetSetter(string name); } class CustomObject : IAccessibleObject { public object Obj { get; private set; } public readonly List customValues; public CustomObject(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 CompositeObject : IAccessibleObject { public object Obj { get; private set; } public readonly Dictionary accessorDict; public CompositeObject(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 compositeStack; private readonly Configuration configuration; private readonly Dictionary typeIds; private List finalFixes; public DeSerializer( IEnumerable> typeCache, Configuration configuration) { this.configuration = configuration; id2obj = new Dictionary(); compositeStack = 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 compositeStack.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(); compositeStack.Push(new CustomObject(instance)); } else { instance = Activator.CreateInstance(type, true); Dictionary accessorDict = StorableAttribute.GetAutostorableAccessors(instance); compositeStack.Push(new CompositeObject(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) { CustomObject customObject = (CustomObject)compositeStack.Pop(); object deserializedObject = decomposer.DeSerialize(customObject.customValues, type); if ( end.Id != null ) id2obj[(int)end.Id] = deserializedObject; SetValue(end.Name, deserializedObject); } else { CompositeObject compositeObject = (CompositeObject)compositeStack.Pop(); compositeObject.PopulateDefaultValues(); SetValue(end.Name, compositeObject.Obj); } } private void PrimitiveHandler(ISerializationToken token) { PrimitiveToken primitive = (PrimitiveToken)token; Type type = typeIds[(int)primitive.TypeId]; object value = configuration .GetFormatter(type) .DeSerialize(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 = compositeStack.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 (compositeStack.Count == 0) { compositeStack.Push(new CompositeObject(value, new Dictionary())); } else { object accessibleObject = compositeStack.Peek(); if (accessibleObject is CompositeObject) { ((CompositeObject)accessibleObject).SetValue(name, value); } else if (accessibleObject is CustomObject) { ((CustomObject)accessibleObject).AddValue(value); } } } } }