#region License Information
/* HeuristicLab
* Copyright (C) 2002-2015 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 HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
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("F6AD0D2A-275D-4CA1-9557-87CD43260DB0")]
public sealed class Number2StringSerializer : ICompositeSerializer {
[StorableConstructor]
private Number2StringSerializer(bool deserializing) { }
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
}
}
}