using System.Collections.Generic; using System; namespace Persistence { public class DeSerializer { class ParentReference { } delegate void Setter(object value); interface IAccessibleObject { object Obj { get; } Setter GetSetter(string name); } class CustomObject : IAccessibleObject { public object Obj { get { return this.obj; } } private object obj; public List customValues; public CustomObject(object obj) { this.obj = obj; this.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 { return this.obj; } } public object obj; public Dictionary accessorDict; public CompositeObject(object obj, Dictionary accessorDict) { this.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); } public void SetAllDefaultValues() { throw new NotImplementedException(); } public Setter GetSetter(string name) { return (value) => accessorDict[name].Set(value); } } private delegate void Handler(IParseToken token); private Dictionary id2obj; private Dictionary handlers; private Stack compositeStack; private Dictionary primitiveSerializers; private List customSerializers; delegate void Thunk(); private List finalFixes; public DeSerializer( IEnumerable primitiveSerializers, IEnumerable customSerializers) { id2obj = new Dictionary(); compositeStack = new Stack(); handlers = new Dictionary(); handlers.Add(typeof(CompositeStart), new Handler(CompositeStartHandler)); handlers.Add(typeof(CompositeEnd), new Handler(CompositeEndHandler)); handlers.Add(typeof(Primitive), new Handler(PrimitiveHandler)); handlers.Add(typeof(Reference), new Handler(ReferenceHandler)); handlers.Add(typeof(Null), new Handler(NullHandler)); this.primitiveSerializers = new Dictionary(); foreach (IPrimitiveSerializer ps in primitiveSerializers) { this.primitiveSerializers.Add(ps.Type, ps); } this.customSerializers = new List(customSerializers); this.finalFixes = new List(); } public object DeSerialize(IEnumerable tokens) { foreach (IParseToken token in tokens) { handlers[token.GetType()].Invoke(token); } foreach (Thunk fix in this.finalFixes) { fix(); } return compositeStack.Pop().Obj; } private void CompositeStartHandler(IParseToken token) { CompositeStart start = (CompositeStart)token; object instance = null; if (this.FindCustomSerializer(start.Type) != null) { instance = new ParentReference(); compositeStack.Push(new CustomObject(instance)); id2obj.Add(start.Id, instance); } else { instance = Activator.CreateInstance(start.Type); Dictionary accessorDict = StorableAttribute.GetAutostorableAccessors(instance); compositeStack.Push(new CompositeObject(instance, accessorDict)); id2obj.Add(start.Id, instance); } } private void CompositeEndHandler(IParseToken token) { CompositeEnd end = (CompositeEnd)token; ICustomSerializer customSerializer = this.FindCustomSerializer(end.Type); if (customSerializer != null) { CustomObject customObject = (CustomObject)compositeStack.Pop(); object deserializedObject = customSerializer.DeSerialize(customObject.customValues, end.Type); this.id2obj[end.Id] = deserializedObject; this.SetValue(end.Name, deserializedObject); } else { CompositeObject compositeObject = (CompositeObject)compositeStack.Pop(); this.SetValue(end.Name, compositeObject.obj); } } private ICustomSerializer FindCustomSerializer(Type type) { foreach (ICustomSerializer serializer in customSerializers) { if (serializer.CanSerialize(type)) return serializer; } return null; } private void PrimitiveHandler(IParseToken token) { Primitive primitive = (Primitive)token; object value = primitiveSerializers[primitive.Type].DeSerialize(primitive.SerializedValue); this.SetValue(primitive.Name, value); } private void ReferenceHandler(IParseToken token) { Reference reference = (Reference)token; object referredObject = this.id2obj[reference.Id]; this.SetValue(reference.Name, this.id2obj[reference.Id]); if (referredObject is ParentReference) { Setter set = compositeStack.Peek().GetSetter(reference.Name); int id = reference.Id; this.finalFixes.Add(() => set(id2obj[id])); } } private void NullHandler(IParseToken token) { Null nil = (Null)token; this.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); } } } } }