#region License Information /* HeuristicLab * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Linq; using HeuristicLab.Persistence.Auxiliary; using HeuristicLab.Persistence.Core; using HEAL.Attic; using HeuristicLab.Persistence.Default.Xml; using HeuristicLab.Persistence.Default.Xml.Primitive; using HeuristicLab.Persistence.Interfaces; namespace HeuristicLab.Persistence.Default.CompositeSerializers { /// /// Serializes a primitive number type using the ToString() method and an /// approriate precision and parses back the generated string using /// the number type's Parse() method. /// /// This serializer has Priorty below zero and is disabled by default /// but can be useful in generating custom serializers. /// [StorableType("CD4E3C0C-C766-42EA-B968-C6EBD0FAA637")] public sealed class Number2StringSerializer : ICompositeSerializer { [StorableConstructor] private Number2StringSerializer(StorableConstructorFlag _) { } public Number2StringSerializer() { } private static readonly Dictionary numberSerializerMap; private static readonly List numberSerializers = new List { new Bool2XmlSerializer(), new Byte2XmlSerializer(), new SByte2XmlSerializer(), new Short2XmlSerializer(), new UShort2XmlSerializer(), new Int2XmlSerializer(), new UInt2XmlSerializer(), new Long2XmlSerializer(), new ULong2XmlSerializer(), new Float2XmlSerializer(), new Double2XmlSerializer(), new Decimal2XmlSerializer(), }; static Number2StringSerializer() { numberSerializerMap = new Dictionary(); foreach (var s in numberSerializers) { numberSerializerMap[s.SourceType] = s; } } /// /// Determines for every type whether the composite serializer is applicable. /// /// The type. /// /// true if this instance can serialize the specified type; otherwise, false. /// public bool CanSerialize(Type type) { return numberSerializerMap.ContainsKey(Nullable.GetUnderlyingType(type) ?? type); } /// /// Give a reason if possibly why the given type cannot be serialized by this /// ICompositeSerializer. /// /// The type. /// /// A string justifying why type cannot be serialized. /// public string JustifyRejection(Type type) { return string.Format("not a (nullable) number type (one of {0})", string.Join(", ", numberSerializers.Select(n => n.SourceType.Name).ToArray())); } /// /// Formats the specified obj. /// /// The obj. /// public string Format(object obj) { if (obj == null) return "null"; Type type = obj.GetType(); return ((XmlString)numberSerializerMap[Nullable.GetUnderlyingType(type) ?? type].Format(obj)).Data; } /// /// Parses the specified string value. /// /// The string value. /// The type. /// public object Parse(string stringValue, Type type) { if (stringValue == "null") return null; try { return numberSerializerMap[Nullable.GetUnderlyingType(type) ?? type].Parse(new XmlString(stringValue)); } catch (FormatException e) { throw new PersistenceException("Invalid element data during number parsing.", e); } catch (OverflowException e) { throw new PersistenceException("Overflow during number parsing.", e); } } /// /// Defines the Priorty of this composite serializer. Higher number means /// higher prioriy. Negative numbers are fallback serializers that are /// disabled by default. /// All default generic composite serializers have priority 100. Specializations /// have priority 200 so they will be tried first. Priorities are /// only considered for default configurations. /// /// public int Priority { get { return -100; } } /// /// Generate MetaInfo necessary for instance creation. (e.g. dimensions /// necessary for array creation. /// /// An object. /// An enumerable of s. public IEnumerable CreateMetaInfo(object obj) { yield return new Tag(Format(obj)); } /// /// Decompose an object into s, the tag name can be null, /// the order in which elements are generated is guaranteed to be /// the same as they will be supplied to the Populate method. /// /// An object. /// An enumerable of s. public IEnumerable Decompose(object obj) { // numbers are composed just of meta info return new Tag[] { }; } /// /// Create an instance of the object using the provided meta information. /// /// A type. /// The meta information. /// A fresh instance of the provided type. public object CreateInstance(Type type, IEnumerable metaInfo) { var it = metaInfo.GetEnumerator(); try { it.MoveNext(); return Parse((string)it.Current.Value, type); } catch (InvalidOperationException e) { throw new PersistenceException( String.Format("Insufficient meta information to reconstruct number of type {0}.", type.VersionInvariantName()), e); } catch (InvalidCastException e) { throw new PersistenceException("Invalid meta information element type", e); } } /// /// Fills an object with values from the previously generated s /// in Decompose. The order in which the values are supplied is /// the same as they where generated. names might be null. /// /// An empty object instance. /// The tags. /// The type. public void Populate(object instance, IEnumerable tags, Type type) { // numbers are composed just of meta info, no need to populate } } }