Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Core/Serializer.cs @ 1772

Last change on this file since 1772 was 1710, checked in by epitzer, 16 years ago

Check if reference is null before calling GetHashCode. (#605)

File size: 5.2 KB
Line 
1using System.Collections.Generic;
2using System.Collections;
3using System;
4using System.Linq;
5using HeuristicLab.Persistence.Auxiliary;
6using HeuristicLab.Persistence.Interfaces;
7using HeuristicLab.Persistence.Core.Tokens;
8using HeuristicLab.Persistence.Default.Decomposers.Storable;
9using System.Text;
10
11namespace HeuristicLab.Persistence.Core {
12
13  public class Serializer : IEnumerable<ISerializationToken> {
14
15    class ReferenceEqualityComparer : IEqualityComparer<object> {
16
17      public bool Equals(object a, object b) {
18        return Object.ReferenceEquals(a, b);
19      }
20
21      public int GetHashCode(object obj) {
22        if (obj == null)
23          return 0;
24        return obj.GetHashCode();
25      }
26
27    }
28
29    private readonly object obj;
30    private readonly string rootName;
31    private readonly Dictionary<object, int> obj2id;
32    private readonly Dictionary<Type, int> typeCache;
33    private readonly Configuration configuration;
34
35    public List<TypeMapping> TypeCache {
36      get {
37        List<TypeMapping> result = new List<TypeMapping>();
38        foreach (var pair in typeCache) {
39          string serializer = null;
40          IFormatter f = configuration.GetFormatter(pair.Key);
41          if (f != null) {
42            serializer = f.GetType().VersionInvariantName();
43          } else {
44            IDecomposer d = configuration.GetDecomposer(pair.Key);
45            serializer = d.GetType().VersionInvariantName();
46          }
47          result.Add(new TypeMapping(pair.Value, pair.Key.VersionInvariantName(), serializer));
48        }
49        return result;
50      }
51    }
52
53    public Serializer(object obj, Configuration configuration) :
54      this(obj, configuration, "ROOT") { }
55
56    public Serializer(object obj, Configuration configuration, string rootName) {
57      this.obj = obj;
58      this.rootName = rootName;
59      this.configuration = configuration;
60      obj2id = new Dictionary<object, int>(new ReferenceEqualityComparer()) { { new object(), 0 } };
61      typeCache = new Dictionary<Type, int>();
62    }
63
64    IEnumerator IEnumerable.GetEnumerator() {
65      return GetEnumerator();
66    }
67
68    public IEnumerator<ISerializationToken> GetEnumerator() {
69      return Serialize(new DataMemberAccessor(rootName, null, () => obj, null));
70    }
71
72    private IEnumerator<ISerializationToken> Serialize(DataMemberAccessor accessor) {
73      object value = accessor.Get();
74      if (value == null)
75        return NullReferenceEnumerator(accessor.Name);
76      Type type = value.GetType();
77      if (obj2id.ContainsKey(value))
78        return ReferenceEnumerator(accessor.Name, obj2id[value]);
79      if (!typeCache.ContainsKey(type))
80        typeCache.Add(type, typeCache.Count);
81      int typeId = typeCache[type];
82      int? id = null;
83      if (!type.IsValueType) {
84        id = obj2id.Count;
85        obj2id.Add(value, (int)id);
86      }
87      IFormatter formatter = configuration.GetFormatter(type);
88      if (formatter != null)
89        return PrimitiveEnumerator(accessor.Name, typeId, formatter.Format(value), id);
90      IDecomposer decomposer = configuration.GetDecomposer(type);
91      if (decomposer != null)
92        return CompositeEnumerator(accessor.Name, decomposer.Decompose(value), id, typeId, decomposer.CreateMetaInfo(value));
93      throw new PersistenceException(
94          String.Format(
95          "No suitable method for serializing values of type \"{0}\" found\r\n" +
96          "Formatters:\r\n{1}\r\n" +
97          "Decomposers:\r\n{2}",
98          value.GetType().VersionInvariantName(),
99          string.Join("\r\n", configuration.Formatters.Select(f => f.GetType().VersionInvariantName()).ToArray()),
100          string.Join("\r\n", configuration.Decomposers.Select(d => d.GetType().VersionInvariantName()).ToArray())
101          ));
102
103    }
104
105    private IEnumerator<ISerializationToken> NullReferenceEnumerator(string name) {
106      yield return new NullReferenceToken(name);
107    }
108
109    private IEnumerator<ISerializationToken> ReferenceEnumerator(string name, int id) {
110      yield return new ReferenceToken(name, id);
111    }
112
113    private IEnumerator<ISerializationToken> PrimitiveEnumerator(string name,
114        int typeId, ISerialData serializedValue, int? id) {
115      yield return new PrimitiveToken(name, typeId, id, serializedValue);
116    }
117
118    private IEnumerator<ISerializationToken> CompositeEnumerator(
119        string name, IEnumerable<Tag> tags, int? id, int typeId, IEnumerable<Tag> metaInfo) {
120      yield return new BeginToken(name, typeId, id);
121      bool first = true;
122      foreach (var tag in metaInfo) {
123        IEnumerator<ISerializationToken> metaIt = Serialize(new DataMemberAccessor(tag.Value, tag.Name));
124        while (metaIt.MoveNext()) {
125          if (first) {
126            yield return new MetaInfoBeginToken();
127            first = false;
128          }
129          yield return metaIt.Current;
130        }
131      }
132      if (!first) {
133        yield return new MetaInfoEndToken();
134      }
135      foreach (var tag in tags) {
136        IEnumerator<ISerializationToken> it = Serialize(new DataMemberAccessor(tag.Value, tag.Name));
137        while (it.MoveNext())
138          yield return it.Current;
139      }
140      yield return new EndToken(name, typeId, id);
141    }
142
143  }
144
145
146}
Note: See TracBrowser for help on using the repository browser.