我想,这将是一个微不足道的问题,并会立即找到答案,但不知何故互联网证明我的假设是错误的。
我有一个包含几个实体的模型,这些实体之间有所有可能的关联(1对1,1对多,多对多,聚合,组合等)。为简单起见,我们以此为例。我们有一个Person类和一个Car类。这个人可以拥有多辆汽车,但一辆汽车只能属于一个人(所以一对多关系)。现在,在Person中创建List / ArrayList来跟踪他/她的汽车是非常简单的。但是,我想跟踪车主的情况。所以,这些类看起来像这样:
[Serializable]
public class Person
{
[XmlElement]
public List<Car> Cars { get; set; }
[XmlAttribute]
public string Name { get; set; }
public Person()
{
Cars = new List<Car>();
}
}
[Serializable]
public class Car
{
[XmlElement]
public Person Owner { get; set; }
[XmlAttribute]
public string Type { get; set; }
public Car()
{
}
}
但是,我相信,这种结构会在Xml文件中引起无限循环,如下所示:
<Person name="John Doe">
<Cars>
<Car type="Ford">
<Owner>
<Person name="John Doe">
<Cars>
<Car type="Ford">
<Owner>
<Person name="John Doe">
... etc.
我甚至尝试了它,在序列化过程中,我得到了“你需要将XmlChoiceIdentifierAttribute添加到'Owner'成员。”例外。
所以,我有几个问题: 1.有没有办法阻止循环序列化? 2.如果没有,我是否必须为每个类编写自己的序列化器? 这个映射可以吗?还是有其他/更好的方法?我已经考虑过一个中心的'Mapper'类,它会根据ID返回所需的对象......但是,这可以通过SQL完成。我想避免SQL(因为保持应用程序轻量化)。
答案 0 :(得分:3)
XmlSerializer
是一个树序列化器,而不是图形序列化器。最好的办法是在序列化期间避免向后导航,例如:
[XmlIgnore]
public Person Owner { get; set; }
(&#34;父母&#34;和&#34;所有者&#34;几乎总是向后导航)
不幸的是,XmlSerializer
不支持后序列化回调,否则可以添加如下内容:
[WhateverOnAfterDeserialized]
public void OnAfterDeserialized(...) {
foreach(var car in cars) car.Owner = this;
}
其他一些序列化程序做支持序列化回调,但是通过该令牌,其他序列化程序也可能支持全图序列化。例如,DataContractSerializer
可以同时支持回调和完整图形,但它对xml的控制要少得多。
另一种选择是拥有一个自定义集合类型,在添加/删除时维护父属性;例如:
public class Person
{
private readonly CarCollection cars;
public Person() {
cars = new CarCollection(this);
}
[XmlElement]
public CarCollection Cars { get { return cars; } }
...
}
with(CarCollection
):
// add code...
innerList.Add(value);
value.Parent = parent; // this is the field stored in the constructor
就个人而言,我认为这可能有点过头了。
另一种选择是简单地添加一个在反序列化后调用的修复方法,它可以执行任何必要的操作(并向下级联):
public void FixupAfterDeserializer() {
foreach(var car in cars) car.Parent = this;
}
请注意,您必须手动调用此方法。
最后,请注意[Serializable]
不需要XmlSerializer
。