• 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} StackTrace:{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>等。

  • 相关阅读:
    ECNU 3288 成绩计算
    ECNU 3241 字母替换
    ECNU 3243 搜索联系人
    ECNU 2977 成绩排序
    ECNU 2974 统计单词个数
    ECNU 3092 GDP
    【Codeforces Round #693 (Div. 3) D】Even-Odd Game
    【Codeforces Round #693 (Div. 3) C】Long Jumps
    【Codeforces Round #693 (Div. 3) B】Fair Division
    【Codeforces Round #693 (Div. 3) A】Cards for Friends
  • 原文地址:https://www.cnblogs.com/lh218/p/4458599.html
Copyright © 2020-2023  润新知