DatacontractSerializer序列化
DatacontractSerializer在命名空间System.Runtime.Serialization下。它能够序列化DataContract、DataMember标记的类。
一、序列化规则:
1.没有显式声明DataMember特性的成员不会参与序列化。
2.DataMember标记的属性必须是可读可写的,否则会序列化异常。
3.所有元素序列化后都是XmlElement形式(不同于XmlSerializer的XmlAttribute可以将元素序列化到元素属性中)。
4.序列化后的元素顺序:父类元素在前,子类元素在后。同一类型中的数据成员按字母顺序排序。
5.默认的命名空间为http://schemas.datacontract.org/2004/07/+数据契约所在类型的名称。
常用序列化代码:
using System.Xml;
using System.Xml.Serialization;
using System.Runtime.Serialization; namespace ConsoleApplication1
{
public class PublicFunction
{
//序列化到XmlNode
public static void SerializeByDataContract<T>(T t, out XmlNode node)
{
DataContractSerializer datacontractSerializer = new DataContractSerializer(typeof(T));
XmlDocument doc = new XmlDocument();
using (MemoryStream ms = new MemoryStream())
{
datacontractSerializer.WriteObject(ms,t);
ms.Position = 0;
doc.Load(ms);
node = doc.LastChild;
}
}
//反序列化XmlNode中的数据
public static void DeserializeByDataContract<T>(XmlNode node, out T t)
{
DataContractSerializer datacontractSerializer = new DataContractSerializer(typeof(T));
using (XmlReader reader = new XmlNodeReader(node))
{
t=(T)datacontractSerializer.ReadObject(reader);
}
}
//序列化到文件
public static void SerializeByDataContractWhithFile<T>(T t, string file)
{
DataContractSerializer datacontractSerializer = new DataContractSerializer(typeof(T));
using (XmlTextWriter writer = new XmlTextWriter(file, Encoding.UTF8))
{
writer.Formatting = Formatting.Indented;
datacontractSerializer.WriteObject(writer,t);
}
}
//从文件反序列化
public static void DeSerializeByDataContractWhithFile<T>(string file,out T t)
{
t = default(T);
DataContractSerializer datacontractSerializer = new DataContractSerializer(typeof(T));
using (XmlReader reader = new XmlTextReader(file))
{
t=(T)datacontractSerializer.ReadObject(reader);
}
}
}
}
序列化实例:
using System.ServiceModel;
using System.Runtime.Serialization;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Order order = new Order();
PublicFunction.SerializeByDataContractWhithFile<Order>(order, @"D:\1.txt");
}
} [DataContract]
public class OrderBase
{
[DataMember(Name="总价",Order=1)]
public double totalPrice; [DataMember(Name = "消费者", Order = 2)]
public string Customer; [DataMember(Name = "标识", Order = 3)]
public Guid guid; public DateTime time; public OrderBase()
{
time = DateTime.Now;
totalPrice = 86.5;
Customer = "lh";
guid = Guid.NewGuid();
time = DateTime.Now;
}
} [DataContract]
public class Order : OrderBase
{
[DataMember(Name="付款方式",Order=1)]
public string paymentType; public Order()
: base()
{
paymentType = "Cash";
}
}
}
序列化结果:
<Order xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication1">
<总价>86.5</总价>
<消费者>lh</消费者>
<标识>933e5fa0-3655-4369-89db-2257d7db3078</标识>
<付款方式>Cash</付款方式>
</Order>
可以看到OrderBase类的time属性没有使用DataMember特性,不会被序列化。
如下代码,A中的IsSet是只读,没有设置set。
class Program
{
static void Main(string[] args)
{
A a = new A();
XmlNode node = null;
try
{
SerializeByDataContract<A>(a, out node);
}
catch (Exception e)
{
Console.WriteLine("Message:{0} \nStackTrace:{1}", e.Message, e.StackTrace);
}
}
}
[DataContract]
public class A
{
private bool isSet; [DataMember]
public bool IsSet
{
get
{
return isSet;
}
}
}
运行时发生异常,DataMember标识的属性必须是可读可写的,必须有get、set操作。
二、设置最大序列化个数
1.使用下面DataContractSerializer构造函数指定一次可序列化的最大个数。
public DataContractSerializer(Type type, IEnumerable<Type> knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool preserveObjectReferences, IDataContractSurrogate dataContractSurrogate);
//序列化到文件并指定最大序列化个数
public static void SerializeByDataContractWhithFile<T>(T t, string file,int maxItemsIObjectGraph)
{
DataContractSerializer datacontractSerializer = new DataContractSerializer(typeof(T), null, maxItemsInObjectGraph, false, false, null);
using (XmlWriter writer = new XmlTextWriter(file, Encoding.UTF8))
{
datacontractSerializer.WriteObject(writer,t);
}
}
序列化:
class Program
{
static void Main(string[] args)
{
List<Order> listOrder = new List<Order>();
for (int i = 0; i < 10; i++)
{
listOrder.Add(new Order());
}
Order order = new Order();
PublicFunction.SerializeByDataContractWhithFile(listOrder, @"D:\1.txt",50);
}
}
运行后抛出异常,System.Runtime.Serialization.SerializationException: 对象图中可以序列化或反序列化的项目数目上限为“50”。请更改对象图或增加 MaxItemsInObjectGraph 的配额。
listOrder本身算一个对象,Order中DataMember属性设置的字段有4个,Order自身算一个,于是总数为(4+1)*10+1=51个,超过了设置的50上限。
2.DataContractSerializer是WCF默认的序列化器,通过ServiceBehavior设置整个服务的最大序列化数,如果客户端调用InsertOrder方法中的listOrder超过10个,则会报SerializationException异常。
[ServiceBehavior(MaxItemsInObjectGraph=50)]
public class OrderService : IOrderService
{
public void InsertOrder(List<Order> listOrder)
{ }
} [ServiceContract]
public interface IOrderService
{
[OperationContract]
void InsertOrder(List<Order> listOrder);
}
三、保持对象现有引用结构
对于对象中的多个字段指向同一个引用,在序列化时可以选择是否对它们都进行序列化。
//序列化到文件并指定最大序列化个数,是否保证现有引用结构
public static void SerializeByDataContractWhithFile<T>(T t, string file, bool preserverReference)
{
DataContractSerializer datacontractSerializer = new DataContractSerializer(typeof(T), null, int.MaxValue, false, preserverReference, null);
using (XmlWriter writer = new XmlTextWriter(file, Encoding.UTF8))
{
datacontractSerializer.WriteObject(writer, t);
}
}
class Program
{
static void Main(string[] args)
{
CommonTest test = new CommonTest();
test.order2 = test.order1 = new Order();
PublicFunction.SerializeByDataContractWhithFile<CommonTest>(test, @"D:\1.txt", true);
}
}
[DataContract]
public class CommonTest
{
[DataMember]
public Order order1; [DataMember]
public Order order2;
}
序列化后的结果为:
<CommonTest xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
z:Id="1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"
xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication1">
<order1 z:Id="2">
<总价>86.5</总价>
<消费者 z:Id="3">lh</消费者>
<标识>cd792ed6-7701-48bd-817f-57605877b8e4</标识>
<付款方式 z:Id="4">Cash</付款方式></order1>
<order2 z:Ref="2" i:nil="true" />
</CommonTest>
可以看出,并没有对order2进行序列化,因为它们指向同一个引用。
四、对未知类型的处理
1.KnowType特性
标签类似于XmlSerializer的XmlInclude标签,用于声明为基类或者接口的对象,实际指向子类或实现类的对象情况下,可以正确序列化为指定的类型。
class Program
{
static void Main(string[] args)
{
KonwTypeBaseTest test1 = new KnowTypeTest { order = new Order() };
PublicFunction.SerializeByDataContractWhithFile<KonwTypeBaseTest>(test1, @"D:\1.txt"); IKonwType test2 = new KnowTypeTest { order = new Order() };
PublicFunction.SerializeByDataContractWhithFile<IKonwType>(test2, @"D:\2.txt");
}
}
[DataContract]
[KnownType(typeof(KnowTypeTest))]
public abstract class KonwTypeBaseTest
{
}
public interface IKonwType
{
}
[DataContract]
public class KnowTypeTest : KonwTypeBaseTest, IKonwType
{
[DataMember]
public Order order;
}
test1基于基类进行序列化,结果为:
<KonwTypeBaseTest xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
i:type="KnowTypeTest" xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication1">
<order>
<总价>86.5</总价>
<消费者>lh</消费者>
<标识>e954f5ff-c2e2-47ee-86a8-46f9bbf88ce3</标识>
<付款方式>Cash</付款方式>
</order>
</KonwTypeBaseTest>
根节点名称为KonwTypeBaseTest。
test2基于接口进行序列化,结果为:
<z:anyType xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:d1p1="http://schemas.datacontract.org/2004/07/ConsoleApplication1"
i:type="d1p1:KnowTypeTest"
xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<d1p1:order>
<d1p1:总价>86.5</d1p1:总价>
<d1p1:消费者>lh</d1p1:消费者>
<d1p1:标识>fe80c5c1-d44b-4e7a-822e-758f645c99f7</d1p1:标识>
<d1p1:付款方式>Cash</d1p1:付款方式>
</d1p1:order>
</z:anyType>
根结点名称为anyType,意味着客户端可以传入任何类型,因此在WCF操作方法中最好不要使用接口类型的参数。
2.ServiceKonwType
WCF中,在声明ServiceContract的时候通过ServiceKonwType指定涉及的类。
[ServiceContract]
[ServiceKnownType(typeof(KnowTypeTest))]
public interface IOrderService
{
[OperationContract]
void TestAbstract(KonwTypeBaseTest test);
}
五、泛型数据的序列化
class Program
{
static void Main(string[] args)
{
Bill<Test1, Test2> bill = new Bill<Test1, Test2> { t1 = new Test1(), t2 = new Test2() };
PublicFunction.SerializeByDataContractWhithFile<Bill<Test1, Test2>>(bill, @"D:\1.txt");
}
} [DataContract]
public class Bill<T1, T2>
{
[DataMember]
public T1 t1;
[DataMember]
public T2 t2;
}
[DataContract]
public class Test1
{
[DataMember]
public Order order1;
public Test1()
{
order1 = new Order();
}
}
[DataContract]
public class Test2
{
[DataMember]
public Order order2;
public Test2()
{
order2 = new Order();
}
}
序列化结果:
<BillOfTest1Test2HtQdUIlS xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication1">
<t1>
<order1>
<总价>86.5</总价>
<消费者>lh</消费者>
<标识>30764490-8197-45e6-8a2f-2f3b3cda79bf</标识>
<付款方式>Cash</付款方式>
</order1>
</t1>
<t2>
<order2>
<总价>86.5</总价>
<消费者>lh</消费者>
<标识>96424ff5-5f9b-483b-afb2-17c98a8e45de</标识>
<付款方式>Cash</付款方式>
</order2>
</t2>
</BillOfTest1Test2HtQdUIlS>
根结点名称为 类型名称+of+泛型参数实际名称1+泛型参数实际名称2...+命名空间的哈希值。但泛型变量序列化后的实际名称还是Bill定义时的t1和t2。
六、对数据契约集合的序列化
数据契约集合指的还集合中的数据使用了DataContract。如下所示,序列化声明时分别指定类型为Order[],IEnumerable<Order>、IList<Order>、自定义的OrderCollection
序列化后,前3个文件中的结果都是一模一样的。
class Program
{
static void Main(string[] args)
{
Order[] oreders = new Order[] { new Order(), new Order() };
PublicFunction.SerializeByDataContractWhithFile<Order[]>(oreders,@"D:\1.txt");
PublicFunction.SerializeByDataContractWhithFile<IEnumerable<Order>>(oreders, @"D:\2.txt");
PublicFunction.SerializeByDataContractWhithFile<IList<Order>>(oreders, @"D:\3.txt"); OrderCollection collec=new OrderCollection{new Order(),new Order()};
PublicFunction.SerializeByDataContractWhithFile<OrderCollection>(collec, @"D:\4.txt");
}
} [CollectionDataContract(Name = "Orders", Namespace = "http://www.cnblogs.com/lh218",ItemName="Add")]
public class OrderCollection : IEnumerable<Order>
{
private IList<Order> list;
public OrderCollection()
{
list = new List<Order>();
}
public void Add(Order order)
{
list.Add(order);
}
public IEnumerator<Order> GetEnumerator()
{
return list.GetEnumerator();
} System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return list.GetEnumerator();
}
}
<ArrayOfOrder xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication1">
<Order>
<总价>86.5</总价>
<消费者>lh</消费者>
<标识>e55e4643-9a31-487b-b72f-3d46bb80b16e</标识>
<付款方式>Cash</付款方式>
</Order>
<Order>
<总价>86.5</总价>
<消费者>lh</消费者>
<标识>7eedba11-bcdc-432b-8810-db471fcf2da4</标识>
<付款方式>Cash</付款方式>
</Order>
</ArrayOfOrder>
根节点名称为ArrayOfOrder,都将它看为数组类型。
第4个使用了CollectionDataContract特性,并且制定了名称、命名空间、子元素名称,序列化后结果为:
<Orders xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:d1p1="http://schemas.datacontract.org/2004/07/ConsoleApplication1"
xmlns="http://www.cnblogs.com/lh218">
<Add>
<d1p1:总价>86.5</d1p1:总价>
<d1p1:消费者>lh</d1p1:消费者>
<d1p1:标识>41997758-59a0-4d84-aa56-d3bb2426b43a</d1p1:标识>
<d1p1:付款方式>Cash</d1p1:付款方式>
</Add>
<Add>
<d1p1:总价>86.5</d1p1:总价>
<d1p1:消费者>lh</d1p1:消费者>
<d1p1:标识>2d4f4e40-9390-43aa-818b-6e8ec97254e6</d1p1:标识>
<d1p1:付款方式>Cash</d1p1:付款方式>
</Add>
</Orders>
七、字典数据契约
class Program
{
static void Main(string[] args)
{
myDictionart myd = new myDictionart();
Order o1=new Order();
myd.Add(o1.guid,o1);
PublicFunction.SerializeByDataContractWhithFile<myDictionart>(myd, @"D:\1.txt");
PublicFunction.SerializeByDataContractWhithFile<IDictionary<Guid,Order>>(myd, @"D:\2.txt");
}
}
[CollectionDataContract(Name = "Orders", Namespace = "http://www.cnblogs.com/lh218", ItemName = "Add",KeyName="Guid",ValueName="Order")]
public class myDictionart : Dictionary<Guid, Order>
{ }
1.txt内容为:
<Orders xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.cnblogs.com/lh218">
<Add>
<Guid>c263740a-417e-4b10-8892-8e8a03fe6989</Guid>
<Order xmlns:d3p1="http://schemas.datacontract.org/2004/07/ConsoleApplication1">
<d3p1:总价>86.5</d3p1:总价>
<d3p1:消费者>lh</d3p1:消费者>
<d3p1:标识>c263740a-417e-4b10-8892-8e8a03fe6989</d3p1:标识>
<d3p1:付款方式>Cash</d3p1:付款方式>
</Order>
</Add>
</Orders>
2.txt内容为
<ArrayOfKeyValueOfguidOrdermcAJRImr xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<KeyValueOfguidOrdermcAJRImr>
<Key>f98fa454-ebe0-4086-b447-07d948862645</Key>
<Value xmlns:d3p1="http://schemas.datacontract.org/2004/07/ConsoleApplication1">
<d3p1:总价>86.5</d3p1:总价>
<d3p1:消费者>lh</d3p1:消费者>
<d3p1:标识>f98fa454-ebe0-4086-b447-07d948862645</d3p1:标识>
<d3p1:付款方式>Cash</d3p1:付款方式>
</Value>
</KeyValueOfguidOrdermcAJRImr>
</ArrayOfKeyValueOfguidOrdermcAJRImr>
八、序列化Hashtable
using System.Xml;
using System.Runtime.Serialization;
using System.Collections;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Hashtable table = new Hashtable();
Order order=new Order(DateTime.Now,12,"BillOrder");
table.Add(1, order);
Serialize<Hashtable>(table, @"D:\1.txt",new Type[]{typeof(Order)});
}
public static void Serialize<T>(T t, string path,Type[] types)
{
DataContractSerializer ser = new DataContractSerializer(typeof(T), types);
using (XmlTextWriter writer = new XmlTextWriter(path, Encoding.UTF8))
{
writer.Formatting = Formatting.Indented;
ser.WriteObject(writer, t);
}
}
} [DataContract]
public class Order
{
[DataMember]
public DateTime date;
[DataMember]
public int price;
[DataMember]
public string name;
public Order(DateTime date, int price, string name)
{
this.date = date;
this.price = price;
this.name = name;
}
public Order()
{ }
}
}
序列化的结果:
<ArrayOfKeyValueOfanyTypeanyType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<KeyValueOfanyTypeanyType>
<Key xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:int">1</Key>
<Value xmlns:d3p1="http://schemas.datacontract.org/2004/07/ConsoleApplication3" i:type="d3p1:Order">
<d3p1:date>2015-05-17T15:10:32.7811014+08:00</d3p1:date>
<d3p1:name>BillOrder</d3p1:name>
<d3p1:price>12</d3p1:price>
</Value>
</KeyValueOfanyTypeanyType>
</ArrayOfKeyValueOfanyTypeanyType>
Hashtable序列化的根结点名称为ArrayOfKeyValueOfanyTypeanyType,意味着是序列化时将key和value看成object类型。在WCF接口中尽量不要使用Hashtable、IList、IEnumerable、object等不确定类型的接口作为方法参数。或者使用确定类型的泛型版本,IList<T>、IEnumerable<T>等。
DatacontractSerializer序列化的更多相关文章
- DataContractSerializer序列化与反序列化遇到的奇怪问题
private static void Serialize1(string filename, object obj) { var stream = new F ...
- 序列化和反序列化的几种方式(DataContractSerializer)(二)
DataContractSerializer 类 使用提供的数据协定,将类型实例序列化和反序列化为 XML 流或文档. 无法继承此类. 命名空间: System.Runtime.Serializati ...
- 序列化和反序列化的几种方式(DataContractSerializer)
序列化和反序列化的几种方式(DataContractSerializer) DataContractSerializer 类 使用提供的数据协定,将类型实例序列化和反序列化为 XML 流或文档. 无法 ...
- DataContractSerializer数据不一致下序列化
一.数据类型的等效性 例如下面定义的两个类成员名称.定义顺序都不一样,但是在DataContract.DataMember的Name属性作用下,两个类的实例对象序列化后的xml是一样的,因此Or ...
- Entity Framework 6 Recipes 2nd Edition(9-7)译->在WCF服务中序列化代理
9-7. 在WCF服务中序列化代理 问题 从一个查询里返回一个动态代理对象,想要把它序列为一个POCO(Plain-Old CLR Objects)对象. 实现基于POCO实体对象, 在运行时,EF会 ...
- WCF初探-24:WCF序列化和反序列化
前言 WCF包含很多封装的内部机制,这些是我们在编写程序时不会经常看到的.比如上一篇讲解的Message.这一篇我将讲解WCF的另一种内部机制,WCF的序列化和反序列化.通常我们在编写WCF服务程序的 ...
- 【WCF--初入江湖】10 序列化和传输大型数据流
10 序列化和传输大型数据流 1.前言 理解WCF的序列化形式 掌握DataContractSerializer序列化对象 比较性能 比较xmlSerializer序列化对象 大数据量传输设置 修 ...
- WCF技术剖析之十五:数据契约代理(DataContractSurrogate)在序列化中的作用
原文:WCF技术剖析之十五:数据契约代理(DataContractSurrogate)在序列化中的作用 [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经> ...
- WCF技术剖析之十三:序列化过程中的已知类型(Known Type)
原文:WCF技术剖析之十三:序列化过程中的已知类型(Known Type) [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制的节目视频(苏州话) ...
随机推荐
- WPF显示Gif动画
WPF的Image控件不能很好的支持.gif文件.解决办法有如下2种. 1使用MediaElement <MediaElement Source="file://D:\anim.gif ...
- openstack kolla 部署---不同的节点采用不同的物理接口
在 /etc/kolla/globals.yml 文件中删除 neutron_external_interface tunnel_interface api_interface storage_ ...
- composer 学习与推荐资料
今天看了一下composer,前几天开始用包依赖,以前一直都是自己手动配.今天用了composer,要学习的话可以按照以下链接学习: 1 官方文档: http://docs.phpcomposer.c ...
- SpringMVC 的映射
27.1.1 @RequestMapping使用 之前,我们是把@RequestMapping注解放在方法之上,用来给方法绑定一个请求映射.除此以外,@RequestMapping注解还可以放在类的上 ...
- [文文殿下]基本的DP技巧
. 二进制状态压缩动态规划 对于某些情况,如果题目中所给的限制数目比较小,我们可以尝试状态压缩动态规划.例如,题目中给出数据范围\(n<=20\),这个一般情况下是一个状压DP的提示. 状态压缩 ...
- 0基础浅谈反射型xss(2)
0x1:回顾前文疑惑“先闭合,在构造” 上一篇,我们说到了xss的一个触发精髓,“先闭合,在构造”,对于前面的先闭合,我们来简单的解释一下: 首先说,为什么要闭合? 因为HTML标签都是成对出现的 ...
- SQL中DateTime转换成Varchar样式
SQL中DateTime转换成Varchar样式语句及查询结果:Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AMSelect ...
- [转] 测试环境下将centos6.8升级到centos7的操作记录
1)查看升级前的版本信息 lsb_release -a LSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noa ...
- Windows系统下如何在cmd命令窗口中切换Python2.7和Python3.6
针对在同一系统下我们可能安装多个版本的Python,毕竟Python2.7与Python3.6还是有不同的需求,但是在用Cmd命令窗口是我们可能默认的系统变量环境是其中一个版本,当我们需要在cmd命令 ...
- SQL面试题(网络收集)
1. 用一条SQL 语句 查询出每门课都大于80 分的学生姓名 name kecheng fenshu 张三 语文 81 张三 数学 75 李四 ...