using System.Collections.Generic;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO.Compression;
using System.ComponentModel;
[XmlType(TypeName = "MyType", Namespace = "https://DefaultNamespace")]
[XmlElement(ElementName = "myValue", Form = XmlSchemaForm.Unqualified)]
public bool MyValue { get; set; }
public bool SomeOtherValue { get; set; }
public abstract class XmlSerializerKey
static class XmlSerializerHashTable
static Dictionary<object, XmlSerializer> dict;
static XmlSerializerHashTable()
dict = new Dictionary<object, XmlSerializer>();
public static XmlSerializer GetSerializer(XmlSerializerKey key)
if (!dict.TryGetValue(key, out value))
dict[key] = value = key.CreateSerializer();
readonly Type serializedType;
protected XmlSerializerKey(Type serializedType)
this.serializedType = serializedType;
public Type SerializedType { get { return serializedType; } }
public override bool Equals(object obj)
if (ReferenceEquals(this, obj))
else if (ReferenceEquals(null, obj))
if (GetType() != obj.GetType())
XmlSerializerKey other = (XmlSerializerKey)obj;
if (other.serializedType != serializedType)
public override int GetHashCode()
if (serializedType != null)
code ^= serializedType.GetHashCode();
public override string ToString()
return string.Format(base.ToString() + ": for type: " + serializedType.ToString());
public XmlSerializer GetSerializer()
return XmlSerializerHashTable.GetSerializer(this);
protected abstract XmlSerializer CreateSerializer();
public abstract class XmlSerializerWithExtraTypesKey : XmlSerializerKey
static IEqualityComparer<HashSet<Type>> comparer;
readonly HashSet<Type> extraTypes = new HashSet<Type>();
static XmlSerializerWithExtraTypesKey()
comparer = HashSet<Type>.CreateSetComparer();
protected XmlSerializerWithExtraTypesKey(Type serializedType, IEnumerable<Type> extraTypes)
foreach (var type in extraTypes)
this.extraTypes.Add(type);
public Type[] ExtraTypes { get { return extraTypes.ToArray(); } }
public override bool Equals(object obj)
XmlSerializerWithExtraTypesKey other = (XmlSerializerWithExtraTypesKey)obj;
return comparer.Equals(this.extraTypes, other.extraTypes);
public override int GetHashCode()
int code = base.GetHashCode();
code ^= comparer.GetHashCode(extraTypes);
public sealed class XmlSerializerIgnoringDefaultValuesKey : XmlSerializerWithExtraTypesKey
readonly XmlAttributeOverrides overrides;
private XmlSerializerIgnoringDefaultValuesKey(Type serializerType, IEnumerable<Type> ignoreDefaultTypes, XmlAttributeOverrides overrides)
: base(serializerType, ignoreDefaultTypes)
this.overrides = overrides;
public static XmlSerializerIgnoringDefaultValuesKey Create(Type serializerType, IEnumerable<Type> ignoreDefaultTypes, bool recurse)
XmlAttributeOverrides overrides;
Type [] typesWithOverrides;
CreateOverrideAttributes(ignoreDefaultTypes, recurse, out overrides, out typesWithOverrides);
return new XmlSerializerIgnoringDefaultValuesKey(serializerType, typesWithOverrides, overrides);
protected override XmlSerializer CreateSerializer()
if (types == null || types.Length < 1)
return new XmlSerializer(SerializedType);
return new XmlSerializer(SerializedType, overrides);
static void CreateOverrideAttributes(IEnumerable<Type> types, bool recurse, out XmlAttributeOverrides overrides, out Type[] typesWithOverrides)
HashSet<Type> visited = new HashSet<Type>();
HashSet<Type> withOverrides = new HashSet<Type>();
overrides = new XmlAttributeOverrides();
foreach (var type in types)
CreateOverrideAttributes(type, recurse, overrides, visited, withOverrides);
typesWithOverrides = withOverrides.ToArray();
static void AddOverride(XmlAttributeOverrides overrides, Type type, MemberInfo memberInfo)
var xmlElementAttr = memberInfo.GetCustomAttributes<XmlElementAttribute>();
var xmlArrayAttr = memberInfo.GetCustomAttribute<XmlArrayAttribute>();
var xmlArrayItemAttr = memberInfo.GetCustomAttributes<XmlArrayItemAttribute>();
var attrs = new XmlAttributes
foreach (var a in xmlElementAttr)
attrs.XmlElements.Add(a);
foreach (var a in xmlArrayItemAttr)
attrs.XmlArrayItems.Add(a);
overrides.Add(type, memberInfo.Name, attrs);
static void CreateOverrideAttributes(Type type, bool recurse, XmlAttributeOverrides overrides, HashSet<Type> visited, HashSet<Type> withOverrides)
if (type == null || type == typeof(object) || type.IsPrimitive || type == typeof(string) || visited.Contains(type))
foreach (var property in type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
if (overrides[type, property.Name] == null)
if (Attribute.IsDefined(property, typeof(DefaultValueAttribute), true))
AddOverride(overrides, type, property);
foreach (var field in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
if (overrides[type, field.Name] == null)
if (Attribute.IsDefined(field, typeof(DefaultValueAttribute), true))
AddOverride(overrides, type, field);
var baseType = type.BaseType;
CreateOverrideAttributes(baseType, recurse, overrides, visited, withOverrides);
public static void Test()
using var stream = new MemoryStream();
var serializer = XmlSerializerIgnoringDefaultValuesKey.Create(typeof(MyType), new[] { typeof(MyType) }, true).GetSerializer();
using (TextWriter writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
serializer.Serialize(writer, new MyType());
var xml = Encoding.UTF8.GetString(stream.ToArray());
Assert.IsTrue(xml.Contains("<myValue>false</myValue>"));
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 class XmlAssert
public static void AreEqual(
Assert.IsTrue(XNode.DeepEquals(Normalize(expected), Normalize(actual)));
private static XElement Normalize(XElement element)
.OrderBy(a => a.Name.ToString()),
.OrderBy(a => a.Name.ToString())
.Select(e => Normalize(e)));
.OrderBy(a => a.Name.ToString()));
return new XElement(element.Name, element.Attributes()
.OrderBy(a => a.Name.ToString()), element.Value);
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];