码迷,mamicode.com
首页 > 其他好文 > 详细

DatacontractSerializer序列化

时间:2015-04-27 00:01:59      阅读:227      评论:0      收藏:0      [点我收藏+]

标签:

   DatacontractSerializer在命名空间System.Runtime.Serialization下。它能够序列化DataContract、DataMember标记的类。

 一、序列化规则:

  1.没有显式声明DataMember特性的成员不会参与序列化。

  2.所有元素序列化后都是XmlElement形式(不同于XmlSerializer的XmlAttribute可以将元素序列化到元素属性中)。

  3.序列化后的元素顺序:父类元素在前,子类元素在后。同一类型中的数据成员按字母顺序排序。

  4.默认的命名空间为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特性,不会被序列化。

二、设置最大序列化个数

   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

 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(); } }

序列化后,前3个文件中的结果都是一模一样的。

<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>

 

DatacontractSerializer序列化

标签:

原文地址:http://www.cnblogs.com/lh218/p/4458599.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!