XmlSerializer with descendant class and XmlAttributeOverrides

CSharp · Console

/Program.cs

//Workaround for bug report: https://github.com/dotnet/runtime/issues/44701 (issue shown at https://dotnetfiddle.net/W9zCSm)
//Using XmlAttributeOverrides as suggested at https://social.msdn.microsoft.com/Forums/vstudio/en-US/4d70a9b9-0546-478b-8fd1-becee107106a/xmlserializer-fails-when-trying-to-serialize-hidden-property-with-xmlignore

using System;
using System.Xml;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.IO;
using System.Text;

public class Program
{
	public static void Main()
	{
		XmlAttributeOverrides overrides = new XmlAttributeOverrides();

		//Override hiding of members (workarround for XmlIgnore being ignore if defined at descendant class)
  	    //Override order for of members (without this you get E,G,C,D output order)
		overrides.Add(typeof(ToSerialize), "A", new XmlAttributes { XmlIgnore = true, XmlElements = { new XmlElementAttribute(){ Order=1 } } });
		overrides.Add(typeof(ToSerialize), "B", new XmlAttributes { XmlIgnore = true, XmlElements = { new XmlElementAttribute(){ Order=2 } } });
		overrides.Add(typeof(ToSerialize), "C", new XmlAttributes { XmlIgnore = false, XmlElements = { new XmlElementAttribute(){ Order=3 } } } );
		overrides.Add(typeof(ToSerialize), "G", new XmlAttributes { XmlIgnore = false, XmlAnyElements = { new XmlAnyElementAttribute(){ Order=4 } } } );
		overrides.Add(typeof(ToSerialize), "D", new XmlAttributes { XmlIgnore = false, XmlElements = { new XmlElementAttribute(){ Order=5 } } } );
		overrides.Add(typeof(ToSerialize), "H", new XmlAttributes { XmlIgnore = false, XmlAnyElements = { new XmlAnyElementAttribute(){ Order=6 } } } );
		overrides.Add(typeof(ToSerialize), "E", new XmlAttributes { XmlIgnore = false, XmlElements = { new XmlElementAttribute(){ Order=7 } } } );
		
		using(var stream = new MemoryStream()){
			XmlSerializer xmlSer = new XmlSerializer(typeof(ToSerializeA), overrides); //typeof(ToSerialize)
			xmlSer.Serialize(
				stream,
				//new ToSerialize(){}
				new ToSerializeA(){ NoExtraComment = true } //set to false to show the extra comment for H (note that we've set XmlIgnore=false, but can still return an XmlComment or XmlSignificantWhitespace based on this flag)
			);
			
			stream.Position = 0;
			
			using (var reader = new StreamReader(stream, Encoding.UTF8))
			{
				string value = reader.ReadToEnd();
				Console.WriteLine(value);
			}
		}
	}
}

[Serializable]
public partial class ToSerialize
{
    public const string MSG_SERIALIZABLE = "Serializable";
    public const string MSG_NON_SERIALIZABLE = "Non-Serializable";  
	
	public string A { get; set;} = MSG_SERIALIZABLE;
	public virtual string B { get; set;} = MSG_SERIALIZABLE;
	
	[XmlIgnore]
	public string C { get; set;} = MSG_NON_SERIALIZABLE;
	[XmlIgnore]
	public virtual string D { get; set;} = MSG_NON_SERIALIZABLE;
}

public partial class ToSerialize
{
	[XmlIgnore]
	public bool NoExtraComment = false;
	
    public string E { get; set;} = MSG_SERIALIZABLE;
	
	[XmlIgnore]
	public string F { get; set;} = MSG_NON_SERIALIZABLE;
	
	[XmlAnyElement(nameof(G))] //better have a name at XmlAnyElement, else WCF's serialization chokes on it even with every possible ignore attribute being used
	[XmlIgnore, SoapIgnore, IgnoreDataMember] //to be overriden so that comment gets shown
	public XmlCharacterData G {
		get { return new XmlDocument().CreateComment("G (Comment)"); }
		set {} //this is required, if missed it won't emit the comment
	}
	
	[XmlAnyElement(nameof(H))] //better have a name at XmlAnyElement, else WCF's serialization chokes on it even with every possible ignore attribute being used
	[XmlIgnore, SoapIgnore, IgnoreDataMember] //not needed to ignore even via an AttributeOverride, will hide by returning a SignificantWhiteSpace //keeping it for other serialization clients
	public XmlCharacterData H {
		get {
        	return !NoExtraComment?
				new XmlDocument().CreateComment("H (Comment)") :
				new XmlDocument().CreateSignificantWhitespace("");
					} //No comment
		set {} //if this doesn't exists it will just be ignored
	}

}

//-----------------------------------------

[Serializable]
public class ToSerializeA: ToSerialize
{
    [XmlIgnore]
	public new string A { get; set;} = MSG_NON_SERIALIZABLE; //BUG: SHOULDN'T SERIALIZE THIS
	[XmlIgnore]
	public override string B { get; set;} = MSG_NON_SERIALIZABLE; //BUG: SHOULDN'T SERIALIZE THIS

	public new string C { get; set;} = MSG_SERIALIZABLE;
	public override string D { get; set;} = MSG_SERIALIZABLE;
}
;