Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Core/DeSerializer.cs @ 1555

Last change on this file since 1555 was 1553, checked in by epitzer, 16 years ago

Replace final fixes for broken parent references with separation of instance creation with meta information. (#548)

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