将 ISerializable 与 DataContractSerializer 一起使用时,如何阻止序列化程序输出类型信息?
Posted
技术标签:
【中文标题】将 ISerializable 与 DataContractSerializer 一起使用时,如何阻止序列化程序输出类型信息?【英文标题】:When using ISerializable with DataContractSerializer, how do I stop the serializer from outputting type information? 【发布时间】:2010-10-17 04:20:07 【问题描述】:为了更好地控制序列化,我将一个类从[DataContract]
转换为[Serializable]
,同时实现了GetObjectData
和特殊的反序列化构造函数。当我这样做时,发出的 XML 现在具有应用于所有元素的类型信息。我不想要这些多余的信息,我想知道如何通知序列化器不要输出它。
这是使用[DataContract]
的示例代码:
[DataContract(Namespace = "")]
class Test
public Test()
[DataMember]
public Nullable<int> NullableNumber = 7;
[DataMember]
public int Number = 5;
public static void Go()
var test = new Test();
var dcs = new DataContractSerializer(typeof(Test));
using (var s = new StreamWriter("test.xml"))
dcs.WriteObject(s.BaseStream, test);
这会输出以下 XML(注意没有关于 Nullable Number 和 Number 的类型信息——这是所需的输出):
<Test xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<NullableNumber>7</NullableNumber>
<Number>5</Number>
</Test>
如果我把上面的代码修改成如下(添加[Serializable], :ISerializable, 和两个序列化方法):
[Serializable]
class Test : ISerializable
public Test()
public Nullable<int> NullableNumber = 7;
public int Number = 5;
public static void Go()
var test = new Test();
var dcs = new DataContractSerializer(typeof(Test));
using (var s = new StreamWriter("test.xml"))
dcs.WriteObject(s.BaseStream, test);
public Test(SerializationInfo info, StreamingContext context)
NullableNumber = info.GetInt32("NullableNumber");
Number = info.GetInt32("Number");
public void GetObjectData(SerializationInfo info, StreamingContext context)
info.AddValue("NullableNumber", NullableNumber);
info.AddValue("Number", Number);
它现在发出以下 XML。注意添加到每个元素的类型信息 (i:type="x:int")。
<Test xmlns="http://schemas.datacontract.org/2004/07/XMLSerialization" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/2001/XMLSchema">
<NullableNumber i:type="x:int" xmlns="">7</NullableNumber>
<Number i:type="x:int" xmlns="">5</Number>
</Test>
为什么要这样做?如何阻止它这样做?
谢谢!
【问题讨论】:
感谢您的提问,因为它解决了我的问题 :-) 至于“为什么”——在第一个示例中,保证每个条目都是一个字段,因此您可以获得只需查看Test
类型的字段。在第二种情况下,您处于控制之中,因此这些条目根本不必是字段,您可能只是在写入/读取随机数据。
现在有一个解决方案,可从 .NET Framework 4.5 获得。请参阅下面的答案
【参考方案1】:
你需要ISerializable
吗?普通的DataContractSerializer
没有给你什么?如果你切换回这个,它应该可以正常工作。
基本上,通过实现自定义序列化,数据不再是基于契约的 - 所以它必须包含这些额外信息以保证它以后能够理解它。
那么:在这种情况下是否有理由实施ISerializable
?
【讨论】:
我精简了示例以使问题更容易。由于此处未显示的原因,我需要自定义序列化。 在我需要自定义序列化的(一长串)原因中,最大的原因是我需要根据其他信息有条件地输出某些属性。 我不明白您关于“它'必须'包含这些额外信息”的评论。实际上,上面的第一个 XML 示例使用 [Serializable] 反序列化器反序列化就好了,因此反序列化器不需要这种类型信息。【参考方案2】:如果你想完全控制 xml 的序列化,你可以使用 XmlSerializer
public class Test
[XmlIgnore]
public Nullable<int> NullableNumber = 7;
[XmlElement("NullableNumber")]
public int NullableNumberValue
get return NullableNumber.Value;
set NullableNumber = value;
public bool ShouldSerializeNullableNumberValue()
return NullableNumber.HasValue;
[XmlElement]
public int Number = 5;
示例序列化代码:
static void Main(string[] args)
XmlSerializer serializer = new XmlSerializer(typeof(Test));
serializer.Serialize(Console.Out, new Test());
结果:
<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Number>5</Number>
<NullableNumber>7</NullableNumber>
</Test>
【讨论】:
【参考方案3】:从 .Net Framework 4.5(和 .Net Core 1.0)开始,可以使用 DataContractJsonSerializerSettings
类:
DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings
EmitTypeInformation = EmitTypeInformation.Never
;
var dcs = new DataContractSerializer(typeof(Test), settings);
EmitTypeInformation
设置告诉序列化程序在序列化期间不要输出(烦人?)__type
参数。
还有一系列其他有用的设置可用。 Here is the docs page 为DataContractJsonSerializerSettings
。
【讨论】:
以上是关于将 ISerializable 与 DataContractSerializer 一起使用时,如何阻止序列化程序输出类型信息?的主要内容,如果未能解决你的问题,请参考以下文章
Serializable 指示一个类可以序列化;ICloneable支持克隆,即用与现有实例相同的值创建类的新实例(接口);ISerializable允许对象控制其自己的序列化和反序列化过程(接口)(
[网络安全提高篇] 一一二.DataCon Coremail邮件安全竞赛之钓鱼邮件识别及分类