Free cookie consent management tool by TermsFeed Policy Generator

source: branches/New Persistence Exploration/Persistence/Persistence/Core/DeSerializer.cs @ 1435

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

Properly deserialize enumerables with parent references, use single Setter delegate, fix id references of primitive values. (#506)

File size: 5.6 KB
Line 
1using System.Collections.Generic;
2using System;
3using HeuristicLab.Persistence.Interfaces;
4
5namespace HeuristicLab.Persistence.Core { 
6
7  public struct ParentReference {} 
8
9  class CompositeObject {
10
11    public object Obj { get; private set; }
12    public List<Tag> customValues;
13
14    public CompositeObject(object obj) {
15      Obj = obj;
16      customValues = new List<Tag>();
17    }
18
19    public void AddValue(string name, object value, List<DeSerializer.Thunk> finalFixes) {
20      Tag t = new Tag(name, value);
21      t.finalFixes = finalFixes;
22      customValues.Add(t);
23    }
24
25    public Setter GetSetter(string name) {           
26      Tag t = customValues[customValues.Count - 1];     
27      return value => t.Value = value;
28    }
29  } 
30
31  public class DeSerializer {
32
33    private delegate void Handler(ISerializationToken token);
34    public delegate void Thunk();
35
36    private readonly Dictionary<int, object> id2obj;
37    private readonly Dictionary<Type, object> serializerMapping;
38    private readonly Dictionary<Type, Handler> handlers;
39    private readonly Stack<CompositeObject> parentStack;   
40    private readonly Dictionary<int, Type> typeIds;   
41    private List<Thunk> finalFixes;
42
43    public DeSerializer(
44      IEnumerable<TypeMapping> typeCache) {     
45      id2obj = new Dictionary<int, object>();
46      parentStack = new Stack<CompositeObject>();
47      handlers = new Dictionary<Type, Handler> {
48                     {typeof (BeginToken), CompositeStartHandler},
49                     {typeof (EndToken), CompositeEndHandler},
50                     {typeof (PrimitiveToken), PrimitiveHandler},
51                     {typeof (ReferenceToken), ReferenceHandler},
52                     {typeof (NullReferenceToken), NullHandler}
53                   };     
54      typeIds = new Dictionary<int, Type>();
55      serializerMapping = new Dictionary<Type, object>();
56      foreach ( var typeMapping in typeCache ) {
57        Type type = Type.GetType(typeMapping.TypeName);
58        typeIds.Add(typeMapping.Id, type);
59        if (typeMapping.Serializer != null) {
60          Type serializerType = Type.GetType(typeMapping.Serializer);
61          serializerMapping.Add(type, Activator.CreateInstance(serializerType, true));
62        }
63      }
64    }
65
66    public object DeSerialize(IEnumerable<ISerializationToken> tokens) {
67      finalFixes = new List<Thunk>();     
68      foreach (ISerializationToken token in tokens) {
69        handlers[token.GetType()].Invoke(token);
70      }
71      foreach (Thunk fix in finalFixes) {
72        fix();
73      }
74      return parentStack.Pop().Obj;
75    }
76
77    private void CompositeStartHandler(ISerializationToken token) {
78      BeginToken start = (BeginToken)token;
79      object instance;     
80      Type type = typeIds[(int)start.TypeId];
81      IDecomposer decomposer = null;
82      if ( serializerMapping.ContainsKey(type) )
83        decomposer = serializerMapping[type] as IDecomposer;     
84      if (decomposer != null) {       
85        instance = decomposer.CreateInstance(type);
86        if (instance == null)
87          instance = new ParentReference();
88        parentStack.Push(new CompositeObject(instance));       
89      } else {
90        throw new ApplicationException(String.Format(
91          "No suitable method for deserialization of type \"{0}\" found.",
92          type.VersionInvariantName()));
93      }
94      if ( start.Id != null )
95        id2obj.Add((int)start.Id, instance);
96    }
97
98    private void CompositeEndHandler(ISerializationToken token) {
99      EndToken end = (EndToken)token;
100      Type type = typeIds[(int)end.TypeId];
101      IDecomposer decomposer = null;
102      if (serializerMapping.ContainsKey(type))
103        decomposer = serializerMapping[type] as IDecomposer;           
104      if (decomposer != null) {
105        CompositeObject customComposite = (CompositeObject)parentStack.Pop();
106        object deserializedObject =         
107          decomposer.Populate(customComposite.Obj, customComposite.customValues, type);
108        if ( end.Id != null )
109          id2obj[(int)end.Id] = deserializedObject;       
110        SetValue(end.Name, deserializedObject);         
111      } else {
112        throw new ApplicationException(String.Format(
113          "No suitable method for deserialization of type \"{0}\" found.",
114          type.VersionInvariantName()));
115      }
116    }
117
118    private void PrimitiveHandler(ISerializationToken token) {
119      PrimitiveToken primitive = (PrimitiveToken)token;
120      Type type = typeIds[(int)primitive.TypeId];
121      object value = ((IFormatter) serializerMapping[type]).Parse(primitive.SerialData);
122      if ( primitive.Id != null )     
123        id2obj[(int)primitive.Id] = value;
124      SetValue(primitive.Name, value);
125    }
126
127    private void ReferenceHandler(ISerializationToken token) {
128      ReferenceToken reference = (ReferenceToken)token;
129      object referredObject = id2obj[reference.Id];
130      SetValue(reference.Name, id2obj[reference.Id]);
131      if (referredObject is ParentReference) {
132        Setter set = parentStack.Peek().GetSetter(reference.Name);       
133        int id = reference.Id;
134        finalFixes.Add(() => set(id2obj[id]));
135      }
136    }
137
138    private void NullHandler(ISerializationToken token) {
139      NullReferenceToken nullToken = (NullReferenceToken)token;
140      SetValue(nullToken.Name, null);
141    }   
142
143    private void SetValue(string name, object value) {
144      if (parentStack.Count == 0) {       
145        parentStack.Push(new CompositeObject(value));
146      } else {       
147        parentStack.Peek().AddValue(name, value, finalFixes);       
148      }
149    }
150  }
151}
Note: See TracBrowser for help on using the repository browser.