Free cookie consent management tool by TermsFeed Policy Generator

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

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

Fix problem with loading configuration. Properly initialize and register instance for empty types and make sure Formats have comparable hash codes. (#583)

File size: 5.5 KB
Line 
1using System.Collections.Generic;
2using System;
3using HeuristicLab.Persistence.Interfaces;
4using HeuristicLab.Persistence.Core.Tokens;
5
6namespace HeuristicLab.Persistence.Core {
7
8  public class Deserializer {
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    private readonly Dictionary<int, object> id2obj;
54    private readonly Dictionary<Type, object> serializerMapping;
55    private readonly Stack<Midwife> parentStack;
56    private readonly Dictionary<int, Type> typeIds;
57
58    public Deserializer(
59      IEnumerable<TypeMapping> typeCache) {
60      id2obj = new Dictionary<int, object>();
61      parentStack = new Stack<Midwife>();
62      typeIds = new Dictionary<int, Type>();
63      serializerMapping = CreateSerializers(typeCache);
64    }
65
66    private Dictionary<Type, object> CreateSerializers(IEnumerable<TypeMapping> typeCache) {
67      var map = new Dictionary<Type, object>();
68      foreach (var typeMapping in typeCache) {
69        Type type = Type.GetType(typeMapping.TypeName, true);
70        typeIds.Add(typeMapping.Id, type);
71        if (typeMapping.Serializer != null) {
72          Type serializerType = Type.GetType(typeMapping.Serializer);
73          map.Add(type, Activator.CreateInstance(serializerType, true));
74        }
75      }
76      return map;
77    }
78
79    public object Deserialize(IEnumerable<ISerializationToken> tokens) {
80      foreach (ISerializationToken token in tokens) {
81        Type t = token.GetType();
82        if (t == typeof(BeginToken)) {
83          CompositeStartHandler((BeginToken)token);
84        } else if (t == typeof(EndToken)) {
85          CompositeEndHandler((EndToken)token);
86        } else if (t == typeof(PrimitiveToken)) {
87          PrimitiveHandler((PrimitiveToken)token);
88        } else if (t == typeof(ReferenceToken)) {
89          ReferenceHandler((ReferenceToken)token);
90        } else if (t == typeof(NullReferenceToken)) {
91          NullHandler((NullReferenceToken)token);
92        } else if (t == typeof(MetaInfoBeginToken)) {
93          MetaInfoBegin((MetaInfoBeginToken)token);
94        } else if (t == typeof(MetaInfoEndToken)) {
95          MetaInfoEnd((MetaInfoEndToken)token);
96        } else {
97          throw new ApplicationException("invalid token type");
98        }
99      }
100      return parentStack.Pop().Obj;
101    }
102
103    private void CompositeStartHandler(BeginToken token) {
104      Type type = typeIds[(int)token.TypeId];
105      IDecomposer decomposer = null;
106      if (serializerMapping.ContainsKey(type))
107        decomposer = serializerMapping[type] as IDecomposer;
108      if (decomposer == null)
109        throw new ApplicationException(String.Format(
110          "No suitable method for deserialization of type \"{0}\" found.",
111          type.VersionInvariantName()));
112      parentStack.Push(new Midwife(type, decomposer, token.Id));
113    }
114
115    private void CompositeEndHandler(EndToken token) {
116      Type type = typeIds[(int)token.TypeId];
117      Midwife midwife = parentStack.Pop();
118      if (midwife.Obj == null)
119        CreateInstance(midwife);
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.