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

69
在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 属性,详细信息请参见此 MSDN 文档

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


你怎么可能不序列化它,却期望能够反序列化它呢? - Justin
给属性赋一个默认值?还有什么其他方法可以在反序列化期间“不忽略”属性呢? - Sergey Kalinichenko
2
忽略序列化和反序列化的属性很容易,您可以为此指定XmlIgnoreAttribute。在我的情况下,我接受用户在请求中的项目数组,并且对于每个项目,用户可以指定一个操作属性,如果他们想要添加、修改或删除该项目。我希望在GET列表调用中使用相同的模型对象,并且不想返回此操作属性。我预计这将是一个非常普遍的情况。我进行了研究,没有找到任何东西,因此提出了这个问题。 - Manoj
10
一堆不负责任的回复。你们真丢脸。在我的情况下,我想停止对一个属性进行序列化,因为它已经被移动到另一个类中,但如果它已经被序列化,它仍然需要被反序列化。如果我使用XmlIgnore,它将不再被反序列化,数据将会丢失。 - xr280xr
5
我投票支持重新开放这个问题。这是一个非常有用的问题,原作者在末尾添加的解决方案是正确的解决方案。由于这个问题已经关闭,似乎可惜不能将正确答案作为实际答案添加进去。 - HugoRune
显示剩余2条评论
2个回答

49
这是Manoj提出的解决方案:
如果您想禁止特定属性“Foo”的序列化,但仍然能够反序列化它,您可以添加一个方法public bool ShouldSerializeFoo(),并始终返回false。
示例:
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;}
}

这将导致半径无法被序列化,但仍允许它被反序列化。

XMLSerializer需要找到此方法,因此必须将其设为public,为避免污染命名空间,您可以添加EditorBrowsable属性以在IDE中隐藏它。不幸的是,此隐藏仅适用于将该程序集作为DLL引用到当前项目中,而不适用于编辑包含此代码的实际项目。


2
这非常有用。 - rollsch
谢谢你的回答,但我很惊讶微软在.NET中有“魔法”。 - Alex from Jitbit
一些在线示例显示ShouldSerialize为私有--它需要是公共的。 - D. Kermott

47
如果您想在使用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将适用于序列化和反序列化。我正在寻找一种方法,即使提供了属性,也可以进行反序列化,但永远不会对其进行序列化。 - Manoj
8
在序列化时使用:XmlSerializer ser = new XmlSerializer(typeof(YourClass), overrides); 在反序列化时使用:XmlSerializer ser = new XmlSerializer(typeof(YourClass)); 不需要overrides参数。 - fcuesta
谢谢你。这个机制不是很直观。 - xr280xr
我有另一个问题。如果我想要忽略的属性是主类的某个对象的属性,该怎么办?例如,我想忽略城市类的属性,但 objCity 是我正在序列化的 State 类的对象。 :( - Dhanashree
2
使用覆盖构建的序列化器应该被静态缓存以避免内存泄漏;有关详情,请参见 Memory Leak using StreamReader and XmlSerializer - dbc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接