source: trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Number2StringSerializer.cs @ 10896

Last change on this file since 10896 was 10896, checked in by epitzer, 5 years ago

#1802 make the Number2StringSerializer accept nullable numbers

File size: 7.5 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Persistence.Auxiliary;
26using HeuristicLab.Persistence.Core;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28using HeuristicLab.Persistence.Default.Xml;
29using HeuristicLab.Persistence.Default.Xml.Primitive;
30using HeuristicLab.Persistence.Interfaces;
31
32namespace HeuristicLab.Persistence.Default.CompositeSerializers {
33
34  /// <summary>
35  /// Serializes a primitive number type using the ToString() method and an
36  /// approriate precision and parses back the generated string using
37  /// the number type's Parse() method.
38  ///
39  /// This serializer has Priorty below zero and is disabled by default
40  /// but can be useful in generating custom serializers.
41  /// </summary>
42  [StorableClass]
43  public sealed class Number2StringSerializer : ICompositeSerializer {
44
45    [StorableConstructor]
46    private Number2StringSerializer(bool deserializing) { }
47    public Number2StringSerializer() { }
48
49    private static readonly Dictionary<Type, IPrimitiveSerializer> numberSerializerMap;
50    private static readonly List<IPrimitiveSerializer> numberSerializers = new List<IPrimitiveSerializer> {
51      new Bool2XmlSerializer(),
52      new Byte2XmlSerializer(),
53      new SByte2XmlSerializer(),
54      new Short2XmlSerializer(),
55      new UShort2XmlSerializer(),
56      new Int2XmlSerializer(),
57      new UInt2XmlSerializer(),
58      new Long2XmlSerializer(),
59      new ULong2XmlSerializer(),
60      new Float2XmlSerializer(),
61      new Double2XmlSerializer(),
62      new Decimal2XmlSerializer(),
63    };
64
65    static Number2StringSerializer() {
66      numberSerializerMap = new Dictionary<Type, IPrimitiveSerializer>();
67      foreach (var s in numberSerializers) {
68        numberSerializerMap[s.SourceType] = s;
69      }
70    }
71
72    /// <summary>
73    /// Determines for every type whether the composite serializer is applicable.
74    /// </summary>
75    /// <param name="type">The type.</param>
76    /// <returns>
77    ///   <c>true</c> if this instance can serialize the specified type; otherwise, <c>false</c>.
78    /// </returns>
79    public bool CanSerialize(Type type) {
80      return numberSerializerMap.ContainsKey(Nullable.GetUnderlyingType(type) ?? type);
81    }
82
83    /// <summary>
84    /// Give a reason if possibly why the given type cannot be serialized by this
85    /// ICompositeSerializer.
86    /// </summary>
87    /// <param name="type">The type.</param>
88    /// <returns>
89    /// A string justifying why type cannot be serialized.
90    /// </returns>
91    public string JustifyRejection(Type type) {
92      return string.Format("not a (nullable) number type (one of {0})",
93        string.Join(", ", numberSerializers.Select(n => n.SourceType.Name).ToArray()));
94    }
95
96    /// <summary>
97    /// Formats the specified obj.
98    /// </summary>
99    /// <param name="obj">The obj.</param>
100    /// <returns></returns>
101    public string Format(object obj) {
102      if (obj == null) return "null";
103      Type type = obj.GetType();
104      return ((XmlString)numberSerializerMap[Nullable.GetUnderlyingType(type) ?? type].Format(obj)).Data;
105    }
106
107    /// <summary>
108    /// Parses the specified string value.
109    /// </summary>
110    /// <param name="stringValue">The string value.</param>
111    /// <param name="type">The type.</param>
112    /// <returns></returns>
113    public object Parse(string stringValue, Type type) {
114      if (stringValue == "null") return null;
115      try {
116        return numberSerializerMap[Nullable.GetUnderlyingType(type) ?? type].Parse(new XmlString(stringValue));
117      }
118      catch (FormatException e) {
119        throw new PersistenceException("Invalid element data during number parsing.", e);
120      }
121      catch (OverflowException e) {
122        throw new PersistenceException("Overflow during number parsing.", e);
123      }
124    }
125
126
127
128    /// <summary>
129    /// Defines the Priorty of this composite serializer. Higher number means
130    /// higher prioriy. Negative numbers are fallback serializers that are
131    /// disabled by default.
132    /// All default generic composite serializers have priority 100. Specializations
133    /// have priority 200 so they will  be tried first. Priorities are
134    /// only considered for default configurations.
135    /// </summary>
136    /// <value></value>
137    public int Priority {
138      get { return -100; }
139    }
140
141    /// <summary>
142    /// Generate MetaInfo necessary for instance creation. (e.g. dimensions
143    /// necessary for array creation.
144    /// </summary>
145    /// <param name="obj">An object.</param>
146    /// <returns>An enumerable of <see cref="Tag"/>s.</returns>
147    public IEnumerable<Tag> CreateMetaInfo(object obj) {
148      yield return new Tag(Format(obj));
149    }
150
151    /// <summary>
152    /// Decompose an object into <see cref="Tag"/>s, the tag name can be null,
153    /// the order in which elements are generated is guaranteed to be
154    /// the same as they will be supplied to the Populate method.
155    /// </summary>
156    /// <param name="obj">An object.</param>
157    /// <returns>An enumerable of <see cref="Tag"/>s.</returns>
158    public IEnumerable<Tag> Decompose(object obj) {
159      // numbers are composed just of meta info
160      return new Tag[] { };
161    }
162
163    /// <summary>
164    /// Create an instance of the object using the provided meta information.
165    /// </summary>
166    /// <param name="type">A type.</param>
167    /// <param name="metaInfo">The meta information.</param>
168    /// <returns>A fresh instance of the provided type.</returns>
169    public object CreateInstance(Type type, IEnumerable<Tag> metaInfo) {
170      var it = metaInfo.GetEnumerator();
171      try {
172        it.MoveNext();
173        return Parse((string)it.Current.Value, type);
174      }
175      catch (InvalidOperationException e) {
176        throw new PersistenceException(
177          String.Format("Insufficient meta information to reconstruct number of type {0}.",
178          type.VersionInvariantName()), e);
179      }
180      catch (InvalidCastException e) {
181        throw new PersistenceException("Invalid meta information element type", e);
182      }
183    }
184
185    /// <summary>
186    /// Fills an object with values from the previously generated <see cref="Tag"/>s
187    /// in Decompose. The order in which the values are supplied is
188    /// the same as they where generated. <see cref="Tag"/> names might be null.
189    /// </summary>
190    /// <param name="instance">An empty object instance.</param>
191    /// <param name="tags">The tags.</param>
192    /// <param name="type">The type.</param>
193    public void Populate(object instance, IEnumerable<Tag> tags, Type type) {
194      // numbers are composed just of meta info, no need to populate
195    }
196  }
197}
Note: See TracBrowser for help on using the repository browser.