【发布时间】:2009-12-22 00:55:26
【问题描述】:
如何强制 .NET 的 XmlSerializer 将 xsi:type="FooClass" 添加到 FooClass 类型的成员/节点?
场景是一个当前发布的应用,在 v.1 中:
- FooClass 继承 FooBaseClass
- FooPropertyA 在 FooBaseClass 上
- FooPropertyB 在 FooClass 上
- FooBaseClass 用 [XmlInclude(typeof(FooClass))] 修饰
- BazClass 有 FooBaseClass 类型的成员 Foo
- 所有的 Baz.Foo 集合都指向一个 FooClass 实例
- Baz.Foo 的所有用法都需要 FooPropertyB(以及 FooClass 实例与 FooBaseClass)
目标:完全移除 FooBaseClass,将 FooBaseClass 的成员推入 FooClass,同时保持向后序列化兼容性
问题:然后我在 Baz.Foo 序列化中丢失了 xsi:type="FooClass" 属性。
换句话说,XmlSerializer.Serialize 的输出
public class BazClass
{
public BazClass()
{
Foo = new FooClass { A = 5, B = "Hello" };
}
public FooClass Foo { get; set; }
}
public class FooClass
{
public int FooPropertyA { get; set; }
public string FooPropertyB { get; set; }
}
需要
<Baz>
<Foo xsi:type="FooClass">
<FooPropertyA>Hello</FooPropertyA>
<FooPropertyB>5</FooPropertyB>
</Foo>
</Baz>
删除 FooBasClass 很容易,但是 XmlSerializer 不再将 xsi:type="FooClass" 放在 Baz/Foo 上,因此 v.1 XmlSerializer.Deserialize 实例化了一个 FooBaseClass 实例,而不是设置 FooPropertyB,并将其分配给 Foo 属性父 Baz 实例的。因此,任何检查 Baz.Foo 是否为 FooClass 或直接强制转换的代码都会失败。
xsi:type 属性被自动放置在 v.1 代码中
public class BazClass
{
public BazClass()
{
Foo = new FooClass { A = 5, B = "Hello" };
}
public FooBaseClass Foo { get; set; }
}
public class FooClass : FooBaseClass
{
public string FooPropertyB { get; set; }
}
[XmlInclude(typeof(FooClass))]
public class FooBaseClass
{
public int FooPropertyA { get; set; }
}
我认为简短的回答是你不能——至少在没有实现 I(Xml)Serializable 或编写自定义序列化代码的情况下不能。但是,我愿意接受好的建议。同时,我在下面实现了一个 workaround hack,并希望有更优雅的东西,或者至少可以让我以某种方式完全删除 FooBaseClass。
BazClass
{
[XmlElement("Foo")]
public FooBaseClass XmlFoo { get { return Foo; } set { Foo = (StartPicture)value; } }
[XmlIgnore]
public FooClass Foo { get; set; }
}
FooClass : FooBaseClass
{
public int FooPropertyB { get; set; }
public string FooPropertyA { get; set; }
}
[XmlInclude("FooClass")]
FooBaseClass
{
}
【问题讨论】: