Skip to content

IXmlSerializable makes XmlSerializer Deserialize creates instance of base class instead of derived class #101654

Open
@MMariusch

Description

@MMariusch

Description

When a base class implements IXmlSerializable then XmlSerializer Deserializing tries to create an instance of base class and calls it's virtual ReadXml instead of the overriden ReadXml in the derived class.

Reproduction Steps

In the following example the deserializer is trying to make an instance of the base class instead of the derived one.

Repository with an example: https://github.com/MMariusch/Example

The code:

public class TestClass
{
	[XmlElement("AClass", typeof(AClass))]
	List<BaseClass> objects = new List<BaseClass>();
	
	public TestClass(){}
	
	public void SaveToFile()
	{
		objects.Add(new AClass("someString"));
		objects.Add(new AClass("anotherString"));
		var xmlSerializer = new XmlSerializer(typeof(List<BaseClass>));
		using (var writer = new StreamWriter("SaveList.xml"))
		{
			xmlSerializer.Serialize(writer, objects);
		}
	}

	public void LoadFromFile()
	{
		if (File.Exists("SaveList.xml"))
		{
			using (var reader = new StreamReader("SaveList.xml"))
			{
				var deserializedList = new XmlSerializer(typeof(List<BaseClass>)).Deserialize(reader) as List<BaseClass>;
				if (deserializedList != null && deserializedList.Count > 0)
				{
					objects = deserializedList;
				}
			}
		}
	}
}

[XmlInclude(typeof(AClass))]
public class BaseClass : IXmlSerializable
{
	public BaseClass() { }
	public XmlSchema GetSchema() { return null; }
	public virtual void ReadXml(XmlReader reader) 
	{
		Console.Write("It shouldn't be triggered.");
	}
	public virtual void WriteXml(XmlWriter writer) { }
}

public class AClass : BaseClass
{
	private string _stringVar;
	public string StringVar { get => _stringVar; private set => _stringVar = value; }
	public AClass() { }
	public AClass(string stringVar)
	{
		_stringVar = stringVar;
	}

	public override void ReadXml(XmlReader reader)
	{
		reader.MoveToContent();
		var anyElements = !reader.IsEmptyElement;
		reader.ReadStartElement();
		if (anyElements)
		{
			_stringVar = reader.ReadElementContentAsString("StringVar", "");
			reader.ReadEndElement();
		}
	}

	public override void WriteXml(XmlWriter writer)
	{
		writer.WriteAttributeString("xsi", "type", null, "AClass");
		writer.WriteElementString("StringVar", _stringVar);
	}
}

Expected behavior

Should create an instance of the derived class.

Actual behavior

Creates an instance of the base class.

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions