Free cookie consent management tool by TermsFeed Policy Generator

source: branches/New Persistence Exploration/Persistence/Persistence/DeSerializer.cs @ 1329

Last change on this file since 1329 was 1329, checked in by epitzer, 15 years ago

refactoring/resharping

File size: 6.3 KB
Line 
1using System.Collections.Generic;
2using System;
3namespace Persistence {
4  public class DeSerializer {
5
6    class ParentReference {     
7    }
8
9    delegate void Setter(object value);
10
11    interface IAccessibleObject {
12      object Obj { get; }     
13      Setter GetSetter(string name);
14    }
15
16    class CustomObject : IAccessibleObject {
17      public object Obj { get; private set; }
18      public readonly List<object> customValues;
19      public CustomObject(object obj) {
20        Obj = obj;
21        customValues = new List<object>();
22      }
23      public void AddValue(object value) {
24        customValues.Add(value);
25      }
26      public Setter GetSetter(string name) {
27        int index = customValues.Count-1;
28        return value => customValues[index] = value;
29      }
30    }
31
32    class CompositeObject : IAccessibleObject {
33      public object Obj { get; private set; }
34      public readonly Dictionary<string, DataMemberAccessor> accessorDict;
35      public CompositeObject(object obj, Dictionary<string, DataMemberAccessor> accessorDict) {
36        Obj = obj;
37        this.accessorDict = new Dictionary<string, DataMemberAccessor>();
38        foreach (KeyValuePair<string, DataMemberAccessor> pair in accessorDict) {
39          this.accessorDict.Add(
40            pair.Value.Name,
41            pair.Value);
42        }
43      }
44      public void SetValue(string name, object value) {
45        accessorDict[name].Set(value);
46      }
47      public Setter GetSetter(string name) {
48        return value => accessorDict[name].Set(value);
49      }
50    }
51
52    private delegate void Handler(IParseToken token);
53
54    private readonly Dictionary<int, object> id2obj;
55    private readonly Dictionary<Type, Handler> handlers;
56    private readonly Stack<IAccessibleObject> compositeStack;
57
58    private readonly Dictionary<Type, IPrimitiveSerializer> primitiveSerializers;
59    private readonly List<ICompoundSerializer> customSerializers;
60
61    delegate void Thunk();
62    private List<Thunk> finalFixes;
63
64    public DeSerializer() : this(
65      InterfaceInstantiatior.InstantiateAll<IPrimitiveSerializer>(),
66      InterfaceInstantiatior.InstantiateAll<ICompoundSerializer>()) {}   
67
68    public DeSerializer(
69        IEnumerable<IPrimitiveSerializer> primitiveSerializers,
70        IEnumerable<ICompoundSerializer> customSerializers) {
71      id2obj = new Dictionary<int, object>();
72      compositeStack = new Stack<IAccessibleObject>();
73      handlers = new Dictionary<Type, Handler> {
74                     {typeof (CompositeStart), CompositeStartHandler},
75                     {typeof (CompositeEnd), CompositeEndHandler},
76                     {typeof (Primitive), PrimitiveHandler},
77                     {typeof (Reference), ReferenceHandler},
78                     {typeof (Null), NullHandler}
79                   };
80      this.primitiveSerializers = new Dictionary<Type, IPrimitiveSerializer>();
81      foreach (IPrimitiveSerializer ps in primitiveSerializers) {
82        this.primitiveSerializers.Add(ps.Type, ps);
83      }
84      this.customSerializers = new List<ICompoundSerializer>(customSerializers);
85    }
86
87    public object DeSerialize(IEnumerable<IParseToken> tokens) {
88      finalFixes = new List<Thunk>();
89      foreach (IParseToken token in tokens) {
90        handlers[token.GetType()].Invoke(token);
91      }
92      foreach (Thunk fix in finalFixes) {
93        fix();
94      }
95      return compositeStack.Pop().Obj;
96    }
97
98    private void CompositeStartHandler(IParseToken token) {
99      CompositeStart start = (CompositeStart)token;
100      object instance;
101      if (FindCompoundSerializer(start.Type) != null) {
102        instance = new ParentReference();
103        compositeStack.Push(new CustomObject(instance));
104        id2obj.Add(start.Id, instance);       
105      } else {
106        instance = Activator.CreateInstance(start.Type);
107        Dictionary<string, DataMemberAccessor> accessorDict =
108        StorableAttribute.GetAutostorableAccessors(instance);
109        compositeStack.Push(new CompositeObject(instance, accessorDict));
110        id2obj.Add(start.Id, instance);
111      }
112    }
113    private void CompositeEndHandler(IParseToken token) {
114      CompositeEnd end = (CompositeEnd)token;
115      ICompoundSerializer customSerializer = FindCompoundSerializer(end.Type);
116      if (customSerializer != null) {
117        CustomObject customObject = (CustomObject)compositeStack.Pop();
118        object deserializedObject =
119          customSerializer.DeSerialize(customObject.customValues, end.Type);
120        id2obj[end.Id] = deserializedObject;       
121        SetValue(end.Name, deserializedObject);         
122      } else {
123        CompositeObject compositeObject = (CompositeObject)compositeStack.Pop();
124        SetValue(end.Name, compositeObject.Obj);
125      }
126    }
127    private ICompoundSerializer FindCompoundSerializer(Type type) {
128      foreach (ICompoundSerializer serializer in customSerializers) {
129        if (serializer.CanSerialize(type))
130          return serializer;
131      }
132      return null;
133    }
134    private void PrimitiveHandler(IParseToken token) {
135      Primitive primitive = (Primitive)token;
136      object value = primitiveSerializers[primitive.Type].DeSerialize(primitive.SerializedValue);
137      this.SetValue(primitive.Name, value);
138    }
139    private void ReferenceHandler(IParseToken token) {
140      Reference reference = (Reference)token;
141      object referredObject = id2obj[reference.Id];
142      SetValue(reference.Name, id2obj[reference.Id]);
143      if (referredObject is ParentReference) {
144        Setter set = compositeStack.Peek().GetSetter(reference.Name);       
145        int id = reference.Id;
146        finalFixes.Add(() => set(id2obj[id]));
147      }
148    }
149    private void NullHandler(IParseToken token) {
150      Null nil = (Null)token;
151      SetValue(nil.Name, null);
152    }
153    private void SetValue(string name, object value) {
154      if (compositeStack.Count == 0) {
155        compositeStack.Push(new CompositeObject(value, new Dictionary<string, DataMemberAccessor>()));
156      } else {
157        object accessibleObject = compositeStack.Peek();
158        if (accessibleObject is CompositeObject) {
159          ((CompositeObject)accessibleObject).SetValue(name, value);
160        } else if (accessibleObject is CustomObject) {
161          ((CustomObject)accessibleObject).AddValue(value);
162        }
163      }
164    }
165  }
166}
Note: See TracBrowser for help on using the repository browser.