New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IXmlSerializable makes XmlSerializer Deserialize creates instance of base class instead of derived class #101654
Comments
The The generated SaveList.xml is: <?xml version="1.0" encoding="utf-8"?>
<ArrayOfBaseClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<BaseClass xsi:type="AClass">
<StringVar>someString</StringVar>
</BaseClass>
<BaseClass xsi:type="AClass">
<StringVar>anotherString</StringVar>
</BaseClass>
</ArrayOfBaseClass> If BaseClass did not implement IXmlSerializable, then XmlSerializer.Deserialize would recognize AnalysisThe behaviour seems to be the same in .NET 8.0 and in .NET Framework 4.8. XmlSerializer in .NET Framework still includes the legacy C# code generator. That likewise has the same behaviour. The generated C# code can be debugged with this app.config: <configuration>
<system.xml.serialization>
<xmlSerializer useLegacySerializerGeneration="true" />
</system.xml.serialization>
<system.diagnostics>
<switches>
<add name="XmlSerialization.Compilation" value="true" />
</switches>
</system.diagnostics>
</configuration> The deserializer code generators have branches specifically for checking the
Those do not trigger with your sample code; SerializableMapping.DerivedMappings is apparently null. Workaround (or intended use?)If you apply XmlSchemaProviderAttribute, then the deserializer checks the [XmlSchemaProvider(nameof(GetSchema))]
public partial class BaseClass : IXmlSerializable
{
internal static XmlSchema Schema { get; }
= new XmlSchema()
{
Items =
{
new XmlSchemaComplexType()
{
Name = "BaseClass",
},
new XmlSchemaComplexType()
{
Name = "AClass",
ContentModel = new XmlSchemaComplexContent()
{
Content = new XmlSchemaComplexContentExtension()
{
BaseTypeName = new XmlQualifiedName("BaseClass"),
Attributes =
{
new XmlSchemaAttribute()
{
Name = "StringVar",
SchemaTypeName = new XmlQualifiedName("string", ns: XmlSchema.Namespace),
},
},
},
},
},
},
};
public static XmlQualifiedName GetSchema(XmlSchemaSet xs)
{
xs.Add(BaseClass.Schema);
return new XmlQualifiedName("BaseClass");
}
}
[XmlSchemaProvider(nameof(GetSchema))]
public partial class AClass : BaseClass
{
public static new XmlQualifiedName GetSchema(XmlSchemaSet xs)
{
xs.Add(BaseClass.Schema);
return new XmlQualifiedName("AClass");
}
} I don't know how much detail can be omitted from the XML schema. |
Thank you for the answer. If I understand correctly, if I want to add another derived class then I need to modify the scheme. internal static XmlSchema Schema { get; } = new XmlSchema()
{
Items =
{
new XmlSchemaComplexType() { Name = "BaseClass" },
new XmlSchemaComplexType()
{
Name = "AClass", ContentModel = new XmlSchemaComplexContent()
{
Content = new XmlSchemaComplexContentExtension()
{
BaseTypeName = new XmlQualifiedName("BaseClass"), Attributes =
{
new XmlSchemaAttribute()
{ Name = "AStringVar", SchemaTypeName = new XmlQualifiedName("string", ns: XmlSchema.Namespace), },
},
},
},
},
new XmlSchemaComplexType()
{
Name = "BClass", ContentModel = new XmlSchemaComplexContent()
{
Content = new XmlSchemaComplexContentExtension()
{
BaseTypeName = new XmlQualifiedName("BaseClass"), Attributes =
{
new XmlSchemaAttribute()
{ Name = "BStringVar", SchemaTypeName = new XmlQualifiedName("string", ns: XmlSchema.Namespace), },
},
},
},
},
}
}; Unfortunately this doesn't work. The deserializer skips BClass. |
Please show how you define BClass and what goes into the XML file. |
Oops. I forgot to add the XmlInclude attribute. Everything works fine. Thank you. Getting IXmlSerializable to work takes a lot of work. That's why I'm wondering whether this shouldn't be treated as an bug. |
The documentation could be improved for sure. The IXmlSerializable documentation explains how to provide a schema but does not mention that XmlSerializer requires a schema for deserialising instances of a derived class. I think a note about this would be useful in the XmlIncludeAttribute documentation as well. It makes some sense that, by implementing IXmlSerializable, the developer also takes responsibility of choosing the XmlQualifiedName for the |
You are right. An improved documentation would be also really helpful. But personally I would prefer to keep modifications of the base class to a minimum. Currently I've encountered another problem. I changed the BaseClass into an abstract class and updated the XmlSchemaComplexType of "BaseClass" by setting IsAbstract flag to true. Unfortunately I get an error because deserializer tries to create an instance of BaseClass instead of the derived class. I updated my project on repo: https://github.com/MMariusch/Example |
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:
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
The text was updated successfully, but these errors were encountered: