让你的火焰火把准备好的人!互联网上有人建议.NET框架中存在错误! : - )
考虑这个人为的模型:
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; }
}
请注意两个共享相同名称和命名空间的Rider
属性,但这些属性不相关。一个是XML可空,另一个不是。
以下是XML序列化然后反序列化空马骑手的一些代码:
// 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's Rider still null?
Console.WriteLine(barnAfter.Horse.Rider == null ? "null" : "not null");
Horse
的{{1}}属性有Rider
,因此应通过序列化维护其空值。运行上面的代码,输出确实是 null 。到目前为止一切都很好。
现在,这是有趣的部分:交换IsNullable = true
类中Horse
和Motorcycle
属性的顺序,以便Barn
成为第一。
再次运行,现在输出不为空。怎么了?!
我在VS 2008和2010上进行了测试。
为了获得更多乐趣,请尝试将两个Motorcycle
属性设置为不同的类型,例如一个Rider
,另一个string
。那个真的搞砸了int
。
我对如何解决这个问题不感兴趣。那是微不足道的。我的问题是:这是一个错误,还是我误解了什么?
答案 0 :(得分:3)
嗯,在第一种情况下,写入的XML看起来有点像这样:
<Barn>
<Horse>
<Rider xsi:nil="true" xmlns="abc" />
</Horse>
</Barn>
然而在第二种情况下,XML看起来像这样:
<Barn>
<Horse />
</Barn>
所以在第二种情况下,反序列化过程中发生的事情基本上就是:
Barn barn = new Barn();
barn.Hose = new Horse();
因为我们在构造函数中默认设置Rider,所以它被留作“Jim Craig”。
有趣的是,只需更改Barn
中元素的顺序即可撤消行为。要尝试发现更多信息,我们可以使用ILSpy和Sgen.exe进行一些挖掘 - 只需对我们的程序集运行sgen
,然后查看生成的程序集。
我们发现在第一种情况下,两者 Write2_Horse
和Write3_Motorcycle
方法中生成的代码都有一行如下所示:
base.WriteNullableStringLiteral("Rider", "abc", o.Rider);
然而在第二种情况下它看起来像这样:
base.WriteElementString("Rider", "abc", o.Rider);
我看不出为什么改变这样的元素的顺序应该以这种方式改变Horse
和Motorcycle
元素的序列化行为的任何理由,所以简而言之这看起来像对我来说就像XML序列化程序集生成器中的一个错误。
您应该向Microsoft报告: - )