posted at 2020.12.23 06:17 by Administrator
数据协定是一种约定,它要求参与协定的类型以及其成员结构必须匹配,但类型以及成员名称不一定相同。假设A类的协定名称为user_a,P1属性的协定名称为pop_1,P2属性的协定名称为pop_2。用A类的实例序列化之后生成的数据去填充B类的实例,虽然B类的两个属性分别为V1和V2,,但是它所使用的数据协定名称与A类相同,此时是可以顺利进行反序列化的,因为它们都符合数据协定的要求。
数据协定最大的作用是在网络传输中保持数据模型的统一,即使数据的发送方与接收方声明了不同的类型,只要双方遵守数据协定,就可以完成序列化与反序列化。
数据协定在类型定义上应当使用DataContractAttribute,DataMemberAttribute类只应用于类型成员上(一般是字段和属性)。
数据协定也可以进行自定义。DataContractAttribute类和DataMemberAttribute类都公开了Name属性,该属性的作用是改变协定的默认名称(默认名称与类型名称相同)。
有时候并不需要一个类型中所有的成员(属性与字段)都参与序列化,要阻止某个成员被序列化,需要在成员定义是应用IgnoreDataMemberAttribute。
DataContractSerializer 类默认将数据协定以XML格式序列化,若需要序列化JSON格式,就得使用DataContractJsonSerializer类(位于System.Runtime.Serialization.Json命名空间),该类的使用方法与 DataContractSerializer类是一样的,只是输出的数据格式不同而已。
一般会按照以下规则来序列化数据协定的成员。
(1)如果数据协定类型具有继承关系,那么基类成员会优先进行序列化,然后再处理派生类的成员。
(2)如果设置了DataMemberAttribute.Order属性,将按照该顺序进行处理。否则,将按照字母顺序排序。
最令人激动人心的是,DataContractSerializerSettings类的PreserveObjectReferences属性为保留引用选项,将它设置为true,可以大量缩减文档的长度。
主要原理是,在开启保留实例引用选项后,在序列化的时候会为每个实例分配一个id,以保证每个实例在序列化时只生成一次。如果某个实例被多个成员引用,那么只有该实例第一次出现时才会填充数据,随后对该实例的引用都使用为实例所分配的id。
下面举例说明:
步骤1:新建一个控制台应用程序项目。
步骤2:声明两个类,它们都是数据协定,并且OrderInfo类的DetailData属性引用OrderDetail的实例。
[DataContract]
public class OrderDetails
{
[DataMember]
public string ContactName { get; set; }
[DataMember]
public decimal Price { get; set; }
[DataMember]
public int Quantity { get; set; }
[DataMember]
public float Weight { get; set; }
}
[DataContract]
public class OrderInfo
{
[DataMember]
public int OrderNo { get; set; }
[DataMember]
public DateTime BuildTime { get; set; }
[DataMember]
public OrderDetails DetailsData { get; set; }
}
步骤3:执行序列化。
using (FileStream fs = File.Open("data.xml", FileMode.Create))
{
OrderDetails dtl = new OrderDetails
{
ContactName = "Fish",
Price = 3.15M,
Quantity = 12,
Weight = 17.5f
};
OrderInfo[] ords =
{
new OrderInfo
{
OrderNo = 1,
BuildTime = new DateTime(2018, 3, 27),
DetailsData = dtl
},
new OrderInfo
{
OrderNo = 2,
BuildTime = new DateTime(2018, 9, 2),
DetailsData = dtl
}
};
DataContractSerializer sz = new DataContractSerializer(ords.GetType());
sz.WriteObject(fs, ords);
}
在未开启引用保留选项时,序列化后得到的XML文档如下.
<ArrayOfOrderInfo xmlns="…" xmlns:i="…">
<OrderInfo>
<BuildTime>2018-03-27T00:00:00</BuildTime>
<DetailsData>
<ContactName>Fish</ContactName>
<Price>3.15</Price>
<Quantity>12</Quantity>
<Weight>17.5</Weight>
</DetailsData>
<OrderNo>1</OrderNo>
</OrderInfo>
<OrderInfo>
<BuildTime>2018-09-02T00:00:00</BuildTime>
<DetailsData>
<ContactName>Fish</ContactName>
<Price>3.15</Price>
<Quantity>12</Quantity>
<Weight>17.5</Weight>
</DetailsData>
<OrderNo>2</OrderNo>
</OrderInfo>
</ArrayOfOrderInfo>
可以看出,OrderDetails实例的各个属性值被写入了两次。
步骤4:对序列化的代码进行修改,开启保留引用选项。
using (FileStream fs = File.Open("data.xml", FileMode.Create))
{
… …
DataContractSerializerSettings settings = new DataContractSerializerSettings();
settings.PreserveObjectReferences = true;
DataContractSerializer sz = new DataContractSerializer(ords.GetType(),settings);
sz.WriteObject(fs, ords);
}
步骤5:运行应用程序,保留对象引用后生成的XML文档如下。
此次OrderDetails实例的各个属性值只写入了一次,第二次是通过id引用的,即上述XML文档中的z:Ref=”3”。
ef46e6a7-65a6-4e18-877d-6bb390edcd50|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04
Tags: 程序, 代码, 方法, 类, 命名空间, 模, 数据
IT技术