using System.Collections.Generic;
using System.Collections;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.IO.Compression;
using System.Collections.ObjectModel;
[DataContract(Name = "GenericTaskItem", Namespace = "http://www.contoso.com")]
abstract public class GenericTaskItem
public string sItemID = "";
protected List<bool> lTimesAnsweredCorrectly = new List<bool>();
[DataContract(Name = "GenericTaskItemConcrete", Namespace = "http://www.contoso.com")]
public class GenericTaskItemConcrete : GenericTaskItem
public List<bool> TimesAnsweredCorrectly { get => lTimesAnsweredCorrectly; }
[DataContract(Name = "GenericTaskItem", Namespace = "http://www.contoso.com")]
abstract public class GenericTaskItem
public string sItemID = "";
protected List<bool> lTimesAnsweredCorrectly = new List<bool>();
[DataMember(Name = "lTimesAnsweredCorrectly")]
XmlBoolList lTimesAnsweredCorrectlySurrogate { get => lTimesAnsweredCorrectly == null ? null : new XmlBoolList(lTimesAnsweredCorrectly); set => lTimesAnsweredCorrectly = value?.List; }
[DataContract(Name = "GenericTaskItemConcrete", Namespace = "http://www.contoso.com")]
public class GenericTaskItemConcrete : GenericTaskItem
public List<bool> TimesAnsweredCorrectly { get => lTimesAnsweredCorrectly; }
[CollectionDataContract(Name = "ArrayOfboolean", ItemName = "boolean", Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
public class XmlBoolList : ConvertingList<bool, List<bool>, string>
public XmlBoolList(List<bool> list) : base(() => list, b => XmlConvert.ToString(b), s => XmlConvert.ToBoolean(s)) { }
public XmlBoolList() : this(new List<bool>()) { }
[CollectionDataContract(Name = "ArrayOfint", ItemName = "int", Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
public class XmlIntList : ConvertingList<int, List<int>, string>
public XmlIntList(List<int> list) : base(() => list, i => XmlConvert.ToString(i), s => XmlConvert.ToInt32(s)) { }
public XmlIntList() : this(new List<int>()) { }
public class ConvertingList<TIn, TList, TOut> : IList<TOut> where TList : IList<TIn>
readonly Func<TList> getList;
readonly Func<TIn, TOut> toOuter;
readonly Func<TOut, TIn> toInner;
public ConvertingList(Func<TList> getList, Func<TIn, TOut> toOuter, Func<TOut, TIn> toInner)
if (getList == null || toOuter == null || toInner == null)
throw new ArgumentNullException();
public TList List => getList();
TIn ToInner(TOut outer)=> toInner(outer);
TOut ToOuter(TIn inner)=> toOuter(inner);
#region IList<TOut> Members
public int IndexOf(TOut item) => List.IndexOf(toInner(item));
public void Insert(int index, TOut item) => List.Insert(index, ToInner(item));
public void RemoveAt(int index) => List.RemoveAt(index);
public TOut this[int index] { get => ToOuter(List[index]); set => List[index] = ToInner(value); }
#region ICollection<TOut> Members
public void Add(TOut item) => List.Add(ToInner(item));
public void Clear() => List.Clear();
public bool Contains(TOut item) => List.Contains(ToInner(item));
public void CopyTo(TOut[] array, int arrayIndex)
foreach (var item in this)
array[arrayIndex++] = item;
public int Count => List.Count;
public bool IsReadOnly => List.IsReadOnly;
public bool Remove(TOut item) => List.Remove(ToInner(item));
#region IEnumerable<TOut> Members
public IEnumerator<TOut> GetEnumerator()
foreach (var item in List)
yield return ToOuter(item);
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
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 Test()
TestGenericTaskItemConcrete();
static void TestGenericTaskItemConcrete()
var old = new VOld.GenericTaskItemConcrete
TimesAnsweredCorrectly = { true, false, true }
var xmlOld = old.ToContractXml();
var newItem = DataContractSerializerHelper.FromContractXml<VNew.GenericTaskItemConcrete>(xmlOld);
Assert.That(old.TimesAnsweredCorrectly.SequenceEqual(newItem.TimesAnsweredCorrectly));
var xmlNew = newItem.ToContractXml();
Console.WriteLine(xmlNew);
Assert.AreEqual(xmlOld, xmlNew);
var newItem2 = DataContractSerializerHelper.FromContractXml<VNew.GenericTaskItemConcrete>(xmlNew);
Assert.That(old.TimesAnsweredCorrectly.SequenceEqual(newItem2.TimesAnsweredCorrectly));
static void TestXmlBoolList()
var values = new List<bool> { true, false, true };
var xml = values.ToContractXml();
var surrogate = new XmlBoolList(values);
var surrogateXml = surrogate.ToContractXml();
Assert.AreEqual(xml, surrogateXml);
var surrogate2 = DataContractSerializerHelper.FromContractXml<XmlBoolList>(xml);
Assert.That(surrogate2.List.SequenceEqual(values));
static void TestXmlIntList()
var values = new List<int> { 1, 0, 1010101 };
var xml = values.ToContractXml();
var surrogate = new XmlIntList(values);
var surrogateXml = surrogate.ToContractXml();
Assert.AreEqual(xml, surrogateXml);
var surrogate2 = DataContractSerializerHelper.FromContractXml<XmlIntList>(xml);
Assert.That(surrogate2.List.SequenceEqual(values));
public static void Main()
Console.WriteLine("Environment version: {0} ({1}), OS: {2}.", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription, Environment.Version, Environment.OSVersion);
Console.WriteLine("Failed with unhandled exception: ");