Free cookie consent management tool by TermsFeed Policy Generator

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

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

Central persistence configuration class. (#506)

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