.NET XmlSerializer error when two classes have properties with the same name

Let your burning torches cook people! Someone from the Internet assumes that there is an error in the .NET Framework! :-)

Consider this contrived model:

public class Barn { public Horse Horse { get; set; } public Motorcycle Motorcycle { get; set; } } public class Horse { public Horse() { Rider = "Jim Craig"; } [XmlElement(IsNullable = true, Namespace = "abc")] public string Rider { get; set; } } public class Motorcycle { public Motorcycle() { Rider = "Ghost"; } [XmlElement(IsNullable = false, Namespace = "abc")] public string Rider { get; set; } } 

Notice two Rider properties that have the same name and namespace, but are otherwise unrelated. One of them is nullable XML, and the other is not.

Here is the code to serialize the XML, and then deserialize the null rider:

 // Create a Barn, with a Horse, with a null Rider Barn barnBefore = new Barn(); barnBefore.Horse = new Horse(); barnBefore.Horse.Rider = null; // Serialize and then deserialize the Barn XmlSerializer serializer = new XmlSerializer(typeof(Barn)); MemoryStream stream = new MemoryStream(); serializer.Serialize(stream, barnBefore); stream.Seek(0, SeekOrigin.Begin); Barn barnAfter = (Barn)serializer.Deserialize(stream); // Is the Horse Rider still null? Console.WriteLine(barnAfter.Horse.Rider == null ? "null" : "not null"); 

The Horse Rider property has IsNullable = true , so its zero value must be maintained through serialization. By executing the above code, the output is really null . So far so good.

Now for the fun part: replace the order of the Horse and Motorcycle properties in the Barn class so that Motorcycle first appears.

Run it again, and now the output is not null . What the heck?!

I tested VS 2008 and 2010.

For more fun, try making two Rider properties of different types, for example, one a string and the other a int . It really XmlSerializer up the XmlSerializer .

I am not interested in getting around this problem. This is trivial. My question is: is this a mistake, or what am I misunderstanding?

+4
source share
1 answer

Well, in the first case, the written XML looks something like this:

 <Barn> <Horse> <Rider xsi:nil="true" xmlns="abc" /> </Horse> </Barn> 

However, in the second case, the XML looks like this:

 <Barn> <Horse /> </Barn> 

Thus, in the second case, what is essential during deserialization is the following:

 Barn barn = new Barn(); barn.Hose = new Horse(); 

So, since we set the default Rider in the constructor, it remains as "Jim Craig."

Interestingly, the behavior can be changed simply by changing the order of the elements in Barn . To try to find more, we can do some digging using ILSpy and Sgen.exe - just run sgen against our assembly and look into the generated assembly.

We found that in the first case, the generated code in and the Write2_Horse and Write3_Motorcycle have a line that looks like this:

 base.WriteNullableStringLiteral("Rider", "abc", o.Rider); 

However, in the second case, it looks like this:

 base.WriteElementString("Rider", "abc", o.Rider); 

I see no reason why changing the order of such elements should change the serialization behavior of both Horse and Motorcycle elements in such a way, so, in short, this seems like an error to me in the XML serialization assembly generator.

You should probably report this to Microsoft :-)

+3
source

Source: https://habr.com/ru/post/1348038/


All Articles