using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Xml.Serialization;
using System.Runtime.Serialization;
public class MyType : IParsable<MyType>
public MyType(string? value1, string? value2) => (this.Value1, this.Value2) = (value1, value2);
public string? Value1 { get; }
public string? Value2 { get; }
public override string ToString() => JsonSerializer.Serialize(this);
public static MyType Parse (string s, IFormatProvider? provider) => JsonSerializer.Deserialize<MyType>(s) ?? throw new ArgumentException();
public static bool TryParse (string? s, IFormatProvider? provider, out MyType result) => throw new NotImplementedException("not needed for the question");
public sealed class ParsableSurrogate<TSelf> where TSelf : IParsable<TSelf>
public TSelf? Value { get; set; }
public string? TextValue { get { return Value?.ToString(); } set { Value = (value == null ? default : TSelf.Parse(value, default)); } }
public class SerializationSurrogateProvider : ISerializationSurrogateProvider
readonly Dictionary<Type, (Type SurrogateType, Func<object, Type, object> ToSurrogate)> toSurrogateDictionary = new();
readonly Dictionary<Type, (Type OriginalType, Func<object, Type, object> ToOriginal)> fromSurrogateDictionary = new();
public Type GetSurrogateType(Type type) =>
toSurrogateDictionary.TryGetValue(type, out var entry) ? entry.SurrogateType : type;
public object GetObjectToSerialize(object obj, Type targetType) =>
toSurrogateDictionary.TryGetValue(obj.GetType(), out var entry) ? entry.ToSurrogate(obj, targetType) : obj;
public object GetDeserializedObject(object obj, Type targetType) =>
fromSurrogateDictionary.TryGetValue(obj.GetType(), out var entry) ? entry.ToOriginal(obj, targetType) : obj;
public SerializationSurrogateProvider AddParsable<TParsable>() where TParsable : IParsable<TParsable>
toSurrogateDictionary.Add(typeof(TParsable), (typeof(ParsableSurrogate<TParsable>), (obj, t) => new ParsableSurrogate<TParsable> { Value = (TParsable)obj }));
fromSurrogateDictionary.Add(typeof(ParsableSurrogate<TParsable>), (typeof(TParsable), (obj, t) => ((ParsableSurrogate<TParsable>)obj).Value!));
public List<MyType?> MyTypes { get; set; } = new ();
public static void Test()
public static void TestMyType()
var model = new MyType("hello", "there");
var serializer = new DataContractSerializer(model.GetType());
serializer.SetSerializationSurrogateProvider(new SerializationSurrogateProvider().AddParsable<MyType>());
var xml = model.ToContractXml(serializer : serializer);
var model2 = DataContractSerializerHelper.FromContractXml<MyType>(xml, serializer);
Assert.That(model.Value1 == model2?.Value1 && model.Value2 == model2?.Value2);
public static void TestNested()
MyTypes = { new MyType("hello", "there"), null, new MyType("foo", "bar") },
var serializer = new DataContractSerializer(model.GetType());
serializer.SetSerializationSurrogateProvider(new SerializationSurrogateProvider().AddParsable<MyType>());
var xml = model.ToContractXml(serializer : serializer);
var model2 = DataContractSerializerHelper.FromContractXml<Model>(xml, serializer);
Assert.That(model2 != null);
Assert.AreEqual(model.MyTypes.Count, model2?.MyTypes.Count);
Assert.That(model.MyTypes.Select(m => m?.ToString()).SequenceEqual(model2!.MyTypes.Select(m => m?.ToString())));
var xml2 = model2.ToContractXml(serializer : serializer);
Assert.AreEqual(xml, xml2);
public static partial class DataContractSerializerHelper
public static string ToContractXml<T>(this T obj, DataContractSerializer? serializer = null, XmlWriterSettings? settings = null)
serializer = serializer ?? new DataContractSerializer(obj == null ? typeof(T) : obj.GetType());
using (var textWriter = new StringWriter())
settings = settings ?? new XmlWriterSettings { Indent = true };
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
serializer.WriteObject(xmlWriter, obj);
return textWriter.ToString();
public static T? FromContractXml<T>(string xml, DataContractSerializer? serializer = null)
using (var textReader = new StringReader(xml ?? ""))
using (var xmlReader = XmlReader.Create(textReader))
return (T?)(serializer ?? new DataContractSerializer(typeof(T))).ReadObject(xmlReader);
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: ");