using System.Collections.Generic;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO.Compression;
using System.Configuration;
using System.ComponentModel;
public sealed class Setting<T> : SettingBase, IXmlSerializable
public Setting(T value, string description)
Description = description;
public Setting(string command, T value, string description)
: this(value, description)
public XmlSchema GetSchema() { return null;}
public void ReadXml(XmlReader reader)
XmlSerializationExtensions.ReadIXmlSerializable(reader, r => true,
Command = r.ReadElementContentAsString();
var serializer = XmlSerializerFactory.Create(typeof(T), "Value", reader.NamespaceURI);
Value = (T)serializer.Deserialize(r);
r => true, r => { Description += r.Value; return true; });
public void WriteXml(XmlWriter writer)
XmlSerializationExtensions.WriteIXmlSerializable(writer, w => { },
w.WriteComment(Description);
w.WriteElementString("Command", Command);
var serializer = XmlSerializerFactory.Create(typeof(T), "Value", null);
serializer.Serialize(w, Value);
public string Description { get; set; }
public string Command { get; set; }
public T Value { get; set; }
public override object ValueUntyped { get { return Value; } }
public abstract class SettingBase
public abstract object ValueUntyped { get; }
public static class XmlSerializationExtensions
public static void ReadIXmlSerializable(XmlReader reader, Func<XmlReader, bool> handleXmlAttribute, Func<XmlReader, bool> handleXmlElement, Func<XmlReader, bool> handleXmlText, Func<XmlReader, bool> handleXmlComment)
if (reader.NodeType != XmlNodeType.Element)
throw new XmlException(string.Format("Invalid NodeType {0}", reader.NodeType));
if (reader.HasAttributes)
for (int i = 0; i < reader.AttributeCount; i++)
reader.MoveToAttribute(i);
handleXmlAttribute(reader);
if (reader.IsEmptyElement)
reader.ReadStartElement();
while (reader.NodeType != XmlNodeType.EndElement)
if (reader.NodeType == XmlNodeType.Element)
using (var subReader = reader.ReadSubtree())
subReader.MoveToContent();
handleXmlElement(subReader);
else if (reader.NodeType == XmlNodeType.Text || reader.NodeType == XmlNodeType.CDATA)
var type = reader.NodeType;
if (reader.NodeType != type)
throw new XmlException(string.Format("handleXmlText incorrectly advanced the reader to a new node {0}", reader.NodeType));
else if (reader.NodeType == XmlNodeType.Comment)
var type = reader.NodeType;
handleXmlComment(reader);
if (reader.NodeType != type)
throw new XmlException(string.Format("handleXmlComment incorrectly advanced the reader to a new node {0}", reader.NodeType));
public static void ReadIXmlSerializable(XmlReader reader, Func<XmlReader, bool> handleXmlAttribute, Func<XmlReader, bool> handleXmlElement, Func<XmlReader, bool> handleXmlText)
ReadIXmlSerializable(reader, handleXmlAttribute, handleXmlElement, handleXmlText, r => true);
public static void WriteIXmlSerializable(XmlWriter writer, Action<XmlWriter> writeAttributes, Action<XmlWriter> writeNodes)
public static class XmlSerializerFactory
readonly static Dictionary<Tuple<Type, string, string>, XmlSerializer> cache;
readonly static object padlock;
static XmlSerializerFactory()
cache = new Dictionary<Tuple<Type, string, string>, XmlSerializer>();
public static XmlSerializer Create(Type serializedType, string rootName, string rootNamespace)
if (serializedType == null)
throw new ArgumentNullException();
if (rootName == null && rootNamespace == null)
return new XmlSerializer(serializedType);
XmlSerializer serializer;
var key = Tuple.Create(serializedType, rootName, rootNamespace);
if (!cache.TryGetValue(key, out serializer))
cache[key] = serializer = new XmlSerializer(serializedType, new XmlRootAttribute { ElementName = rootName, Namespace = rootNamespace });
[XmlRoot("Wrapper", Namespace = "questions/61190548")]
public Setting<T> Setting { get; set; }
public string Text { get; set; }
public static void Test()
Test("my setting value", EqualityComparer<string>.Default.Equals);
Test(new DateTime(2020, 4, 13, 10, 10, 10), EqualityComparer<DateTime>.Default.Equals);
Test(10101.01m, EqualityComparer<decimal>.Default.Equals);
Test(new[] { "string1", "string2" }, (x, y) => x.SequenceEqual(y));
static void Test<T>(T value, Func<T, T, bool> equals)
Console.WriteLine("\nTesting {0} {1}:", typeof(T), value);
TestAsRoot(value, equals);
TestNested(value, equals);
static void TestAsRoot<T>(T value, Func<T, T, bool> equals)
var setting = new Setting<T>("my command", value, "my description");
var xml = setting.GetXml();
var setting2 = xml.LoadFromXml<Setting<T>>();
var xml2 = setting2.GetXml();
Assert.IsTrue(equals(setting.Value, setting2.Value));
Assert.IsTrue(setting.Description == setting2.Description);
Assert.IsTrue(setting.Command == setting2.Command);
Assert.IsTrue(xml == xml2);
static void TestNested<T>(T value, Func<T, T, bool> equals)
var setting = new Setting<T>("my command", value, "my description");
var root = new Wrapper<T> { Setting = setting, Text = "Wrapper Text" };
var root2 = xml.LoadFromXml<Wrapper<T>>();
var setting2 = root2.Setting;
var xml2 = root2.GetXml();
Assert.IsTrue(equals(setting.Value, setting2.Value));
Assert.IsTrue(setting.Description == setting2.Description);
Assert.IsTrue(setting.Command == setting2.Command);
Assert.IsTrue(xml == xml2);
Assert.IsTrue(root.Text == root2.Text);
public static class XmlSerializationHelper
public static T LoadFromXml<T>(this string xmlString, XmlSerializer serial = null)
serial = serial ?? new XmlSerializer(typeof(T));
using (var reader = new StringReader(xmlString))
return (T)serial.Deserialize(reader);
public static string GetXml<T>(this T obj, XmlSerializer serializer = null, bool omitStandardNamespaces = false)
XmlSerializerNamespaces ns = null;
if (omitStandardNamespaces)
ns = new XmlSerializerNamespaces();
using (var textWriter = new StringWriter())
var settings = new XmlWriterSettings() { Indent = true };
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
(serializer ?? new XmlSerializer(obj.GetType())).Serialize(xmlWriter, obj, ns);
return textWriter.ToString();
public static void Main()
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , GetNetCoreVersion());
Console.WriteLine("Failed with unhandled exception: ");
public static string GetNetCoreVersion()
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.CodeBase.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];