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:上面的类和代码仅仅是代码的重建,实际上提出了这个问题。它的结构相似,生成的输出也非常相似。我确实在应用程序中快速实现并测试了这段代码,它似乎显示了我的问题,请原谅我是否在克隆原始代码的基本结构时发生了一些错误。

+0

是否打算用'XmlAttribute'和另一个用'XmlElement'装饰? –

只读属性未被序列化,因为它们无法在往返中反序列化回对象数据。

但是,返回集合的只读属性的规则有一个例外 - >IEnumerable

反向串行程序在返回时执行的操作(当xml再次成为类时)是将元素作为类型添加到集合中。它从来不需要“设置”房产。

注:在你的情况下,如果你尝试反序列化它会炸弹。但如果你改变它使用支持领域,它不会轰炸。

Introducing XML Serialization并注意第3段:

XML序列化不会转换方法,索引器,私有字段, 或只读属性(除只读的集合)。要序列化 所有对象的字段和属性(公有和私有)都使用BinaryFormatter而不是XML序列化。

+0

谢谢,我错过了。那么在我的情况下,最佳做法是什么?我总是希望邻居属性是邻居的名字,所以我可以'私人祖父母_neighbor;私人字符串_neighborName;'并使setter:'公共字符串邻居名称{得到{返回_neighbor!= null? _neighbor.Name:_neighborName; } set {_neighborName = value; }}。我认为这是一个不好的解决方案,因为有人使用这个类可能会认为他可以设置NeighborName属性,但它只是有点被真实邻居属性的名称遮蔽(并且我不想更改该对象的道具)。 – swent

+0

如果它总是被反序列化来创建它,你可以设置一个私有标志来允许它被设置一次,并且在那之后抛出无效的操作异常 – toddmo