using System.Collections.Generic;
using System.Xml.Serialization;
public static partial class XmlExtensions
public static T? Deserialize<T>(this XmlElement element, bool useElementName)
var serializer = useElementName
? XmlSerializerFactory.Create(typeof(T), element.LocalName, element.NamespaceURI)
: new XmlSerializer(typeof(T));
return element.Deserialize<T>(serializer);
public static T? Deserialize<T>(this XmlElement element, XmlSerializer? serializer = null)
using (var reader = new ProperXmlNodeReader(element))
return reader.Deserialize<T>(serializer);
public static T? Deserialize<T>(this XmlReader reader, XmlSerializer? serializer = null)
=> (T?)(serializer ?? new XmlSerializer(typeof(T))).Deserialize(reader);
class ProperXmlNodeReader : XmlNodeReader
public ProperXmlNodeReader(XmlNode node) : base(node) {}
public override string? LookupNamespace(string prefix) => base.LookupNamespace(prefix) is {} ns ? NameTable.Add(ns) : null;
public static class XmlSerializerFactory
readonly static Dictionary<Tuple<Type, string, string>, XmlSerializer> cache = new ();
readonly static object padlock = new ();
public static XmlSerializer Create(Type serializedType, string rootName, string rootNamespace)
if (serializedType == null)
throw new ArgumentNullException();
var key = Tuple.Create(serializedType, rootName, rootNamespace);
if (!cache.TryGetValue(key, out var serializer))
cache[key] = serializer = new XmlSerializer(serializedType, new XmlRootAttribute { ElementName = rootName, Namespace = rootNamespace });
public string TheFooString { set; get; }
public string TheBarString { set; get; }
public List<XmlElement> UnknownElements { get; set; }
public static A Deserialize( string _sXml )
if( _sXml != string.Empty )
XmlSerializer serializer = new XmlSerializer(typeof(A));
XmlReader xmlReader = XmlReader.Create(new StringReader(_sXml));
A instance = (A)serializer.Deserialize(xmlReader);
instance.AfterDeserialize();
public void AfterDeserialize()
if (UnknownElements == null)
for (var i = UnknownElements.Count-1; i >= 0; i--)
var xmlElement = UnknownElements[i];
if( xmlElement.LocalName == "TheFooString" )
var BorrowString = xmlElement.Deserialize<string>(useElementName : true);
TheBarString = BorrowString;
UnknownElements.RemoveAt(i);
Console.WriteLine( ex.ToString() );
public static void Test()
public static void Test1()
var s = "value of TheFooString";
Console.WriteLine(s.GetXml(omitStandardNamespaces : true));
public static void Test2()
var original = new Version1.A { TheFooString = "I'm from Foo.A" };
var xml = original.GetXml();
var test = Version2.A.Deserialize(xml);
Assert.AreEqual(original.TheFooString, test.TheBarString);
Console.WriteLine("Re-serialized {0}:", test);
Console.WriteLine(test.GetXml());
public static partial class XmlExtensions
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, bool omitStandardNamespaces)
return obj.GetXml(null, omitStandardNamespaces);
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() ?? typeof(T))).Serialize(xmlWriter, obj, ns);
return textWriter.ToString();
public static void Main()
Console.WriteLine("Environment version: {0} ({1}, {2})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version, Environment.OSVersion);
Console.WriteLine("Failed with unhandled exception: ");