在 xml 序列化期间忽略属性,但在反序列化期间不忽略

Posted

技术标签:

【中文标题】在 xml 序列化期间忽略属性,但在反序列化期间不忽略【英文标题】:Ignore a property during xml serialization but not during deserialization 【发布时间】:2013-08-17 00:44:00 【问题描述】:

在 C# 中,如何让 XmlSerializer 在序列化期间忽略属性,但在反序列化期间不忽略? (或者我如何对 Json.net 做同样的事情?)

要防止某个属性被序列化,可以添加XmlIgnore 属性:

[XmlIgnore]
public int FooBar get;set;

这将导致序列化过程中省略<FooBar>标签。

不过,这也意味着<FooBar>标签在反序列化时会被忽略。

在我的例子中,我在请求中接受来自用户的一组项目,如果用户想要添加、修改或删除项目,他们可以为每个项目指定一个操作属性。我想为 GET 列表调用使用相同的模型对象,并且不想返回此操作属性。我预计这将是一个很常见的情况。

另一个用例: 假设你有一个圆形对象

public class Circle

    public double Radius  get; set; 

然后你修改它以添加一个直径属性

public class Circle2

    public double Diameter  get; set; 
    public double Radius  get  return Diameter / 2;  set  Diameter = value*2;  

您可能只想序列化直径,但仍然能够反序列化仅包含半径的旧格式的 xml 文件。

我做了我的研究,没有发现任何东西,因此提出了这个问题

解决方案:我想出了解决方案。我可以添加一个总是返回 false 的 ShouldSerialize 属性,详细信息在 this MSDN documentation

(如果重新打开这个问题,这个解决方案可以作为实际答案添加)

【问题讨论】:

你怎么能不序列化它,然后期望它反序列化呢? 给一个属性一个默认值?.. 在反序列化过程中你如何“不忽略”一个属性? 忽略序列化和反序列化的属性很容易,您可以为此指定 XmlIgnoreAttribute。就我而言,我在请求中接受来自用户的一组项目,如果用户想要添加、修改或删除项目,用户可以为每个项目指定一个操作属性。我想为 GET 列表调用使用相同的模型对象,并且不想返回此操作属性。我希望这将是一个很常见的情况。我做了我的研究,没有发现任何东西,因此提出了这个问题。 真是一堆半途而废的回应。为你们感到羞耻。在我的例子中,我想停止序列化一个属性,因为它已经被移动到另一个类,但是如果它已经被序列化,它仍然需要被反序列化。如果我使用 XmlIgnore,它将不再被反序列化并且数据将丢失。 我投票重新提出这个问题。这是一个非常有用的问题,原作者最后添加的解决方案是正确的解决方案。由于问题已关闭,因此无法将正确答案添加为实际答案,这似乎很遗憾。 【参考方案1】:

这是 Manoj 提出的解决方案:

如果您想禁止对特定属性 Foo 进行序列化,但仍能够对其进行反序列化,您可以添加一个始终返回 false 的方法 public bool ShouldSerializeFoo()

例子:

public class Circle2

    public double Diameter  get; set; 
    public double Radius  get  return Diameter / 2;  set  Diameter = value*2;  

    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
    public bool ShouldSerializeRadius() return false;

这将导致 Radius 不被序列化,但仍然允许它被反序列化。

此方法必须是公共的,XMLSerializer 才能找到它,因此为了避免污染命名空间,您可以添加 EditorBrowsable 属性以在 IDE 中隐藏它。不幸的是,只有在当前项目中将程序集作为 DLL 引用时,这种隐藏才有效,但在您使用此代码编辑实际项目时无效。

【讨论】:

这非常有用。 感谢您的回答,但令 MS 在 .NET 中拥有“魔力”感到惊讶【参考方案2】:

如果你想在用 XmlSerializer 序列化时忽略元素,你可以使用 XmlAttributeOverrides:

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes attribs = new XmlAttributes();
attribs.XmlIgnore = true;
attribs.XmlElements.Add(new XmlElementAttribute("YourElementName"));
overrides.Add(typeof(YourClass), "YourElementName", attribs);

XmlSerializer ser = new XmlSerializer(typeof(YourClass), overrides);
ser.Serialize(...

【讨论】:

谢谢 Fcuesta,但 XmlIgnore 将适用于序列化和反序列化。如果提供了属性,我正在寻找一种能够反序列化的方法,但从不序列化它。 序列化时使用:XmlSerializer ser = new XmlSerializer(typeof(YourClass), overrides);反序列化时使用 XmlSerializer ser = new XmlSerializer(typeof(YourClass));没有 overrides 参数 谢谢。这种机制不是很直观。 我还有一个问题。如果我要忽略的属性是对象是主类属性的类的属性怎么办?例如,我想忽略城市类的属性,但 objCity 是我正在序列化的 State 类的对象。 :( 使用覆盖构造的序列化程序应该被静态缓存以避免内存泄漏;详情请参阅Memory Leak using StreamReader and XmlSerializer。

以上是关于在 xml 序列化期间忽略属性,但在反序列化期间不忽略的主要内容,如果未能解决你的问题,请参考以下文章

Jersey 2.8客户端在反序列化期间没有忽略未知属性

在使用 Jackson 反序列化期间选择性地忽略 JSON 属性

在反序列化期间使用 XML 装饰指定默认值

JsonSerializer 在反序列化期间不使用内部构造函数

在反序列化期间获取任何深度的XMLElement

Django REST Framework 序列化程序字段必需=false