C#XML序列化问题{get {...}}
我一直在阅读很多关于c#xml序列化的其他问题,但似乎无法解决这个我有的小理解问题。C#XML序列化问题{get {...}}
我希望它不会太长,请考虑下面的代码:
public class Grandparent {
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
}
public class ParentA : Grandparent {
private Grandparent _neighbor;
[XmlAttribute(AttributeName = "neighbor")]
public string NeighborName { get { return _neighbor.Name; } }
public ParentA() : this(null) { }
public ParentA(Grandparent neighbor) {
setNeighbor(neighbor);
}
public void setNeighbor(Grandparent neighbor) {
// Do some checking
_neighbor = neighbor;
}
}
public class ParentB : Grandparent {
private List<Grandparent> _people;
[XmlElement(ElementName = "child1")]
public List<ChildA1> Children1 { get { return _people.Where(p => p.GetType() == typeof(ChildA1)).Cast<ChildA1>().ToList(); } }
[XmlElement(ElementName = "child2")]
public List<ChildA2> Children2 { get { return _people.Where(p => p.GetType() == typeof(ChildA2)).Cast<ChildA2>().ToList(); } }
[XmlElement(ElementName = "parentc")]
public List<ParentC> ParentsC { get { return _people.Where(p => p.GetType() == typeof(ParentC)).Cast<ParentC>().ToList(); } }
public ParentB() {
_people = new List<Grandparent>();
}
public void AddPerson(Grandparent person) {
// Do some checking
_people.Add(person);
}
}
public class ParentC : Grandparent {
}
public class ChildA1 : ParentA {
}
public class ChildA2 : ParentA {
}
[XmlRoot("myroot")]
public class Model {
private List<ParentB> _parents;
[XmlElement(ElementName = "parentb")]
public List<ParentB> Parents { get { return _parents; } }
public Model() {
_parents = new List<ParentB>();
}
public void AddParent(ParentB parent) {
// Do some checking
_parents.Add(parent);
}
public string Serialize() {
XmlSerializer serializer = new XmlSerializer(typeof(Model));
using (StringWriter writer = new StringWriter()) {
serializer.Serialize(writer, this);
return writer.ToString();
}
}
}
现在让我们创建一个模型,并用一些数据填充它:
Model model = new Model();
ChildA1 child1 = new ChildA1 { Name = "Alex" };
ChildA1 child2 = new ChildA1 { Name = "Ben" };
ChildA2 child3 = new ChildA2 { Name = "Jim" };
ChildA2 child4 = new ChildA2 { Name = "Pete" };
child1.setNeighbor(child2);
child2.setNeighbor(child1);
child3.setNeighbor(child4);
child4.setNeighbor(child3);
ParentB parent1 = new ParentB { Name = "Fred" };
ParentC parent2 = new ParentC { Name = "Sam" };
parent1.AddPerson(parent2);
parent1.AddPerson(child1);
parent1.AddPerson(child2);
parent1.AddPerson(child3);
parent1.AddPerson(child4);
model.AddParent(parent1);
textBox1.Text = model.Serialize();
这是输出XML我们得到:
<?xml version="1.0" encoding="utf-16"?>
<myroot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<parentb name="Fred">
<child1 name="Alex" />
<child1 name="Ben" />
<child2 name="Jim" />
<child2 name="Pete" />
<parentc name="Sam" />
</parentb>
</myroot>
现在我们终于来到了我的问题的原因: 从我的理解只有公共数据才会被序列化,这意味着方法(或从它们返回的数据)不会被序列化。 因此,像public string Test { get; set; }
这样的东西可能会翻译成公共领域......所以可能会被序列化。 但是这个怎么样:public string Test { get { return _someString; } }
? 这只是一个像public string get_Test() { return _someString; }
正常方法的语法糖不是吗?我们知道从方法返回的数据没有被序列化吗?
是的,还有就是证明:
[XmlAttribute(AttributeName = "neighbor")]
public string NeighborName { get { return _neighbor.Name; } }
这不是正在连载。 但是等等..什么?下一个作品:
[XmlElement(ElementName = "child1")]
public List<ChildA1> Children1 { get { return _people.Where(p => p.GetType() == typeof(ChildA1)).Cast<ChildA1>().ToList(); } }
我想我可以说,像public string Test { get { return _someObj.someString; } }
一些简单的getter只是访问一个数据域和可能翻译的东西,可以被序列化?但是上面发布的更复杂的getter确实有效,为什么简单版本(邻居)不起作用? 我必须错过一些东西......它主演着我的眼睛,但我看不到它。
请帮我解决这个谜题。
PS:上面的类和代码仅仅是代码的重建,实际上提出了这个问题。它的结构相似,生成的输出也非常相似。我确实在应用程序中快速实现并测试了这段代码,它似乎显示了我的问题,请原谅我是否在克隆原始代码的基本结构时发生了一些错误。
只读属性未被序列化,因为它们无法在往返中反序列化回对象数据。
但是,返回集合的只读属性的规则有一个例外 - >IEnumerable
。
反向串行程序在返回时执行的操作(当xml再次成为类时)是将元素作为类型添加到集合中。它从来不需要“设置”房产。
注:在你的情况下,如果你尝试反序列化它会炸弹。但如果你改变它使用支持领域,它不会轰炸。
见Introducing XML Serialization并注意第3段:
XML序列化不会转换方法,索引器,私有字段, 或只读属性(除只读的集合)。要序列化 所有对象的字段和属性(公有和私有)都使用BinaryFormatter而不是XML序列化。
谢谢,我错过了。那么在我的情况下,最佳做法是什么?我总是希望邻居属性是邻居的名字,所以我可以'私人祖父母_neighbor;私人字符串_neighborName;'并使setter:'公共字符串邻居名称{得到{返回_neighbor!= null? _neighbor.Name:_neighborName; } set {_neighborName = value; }}。我认为这是一个不好的解决方案,因为有人使用这个类可能会认为他可以设置NeighborName属性,但它只是有点被真实邻居属性的名称遮蔽(并且我不想更改该对象的道具)。 – swent
如果它总是被反序列化来创建它,你可以设置一个私有标志来允许它被设置一次,并且在那之后抛出无效的操作异常 – toddmo
是否打算用'XmlAttribute'和另一个用'XmlElement'装饰? –