概述
XML序列化和反序列化是C#的常用技術,實作的方式有很多種,序列化即将對象轉化為便于傳輸的資料格式, 常見的方法有:二進制,位元組數組,json字元串,xml字元串等。今天主要通過DataContractSerializer類的WriteObject和ReadObject方法實作.上次講過XmlSerializer序列化和反序列化,請參考:
C# XML序列化和反序列化(XmlSerializer)
代碼實作
前台XMAL: 邏輯很簡單,主要通過綁定DisplayInfo顯示相關資訊
<UserControl x:Class="Caliburn.Micro.Hello.DataContractSerializerView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Caliburn.Micro.Hello" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <TextBlock Background="White" Height="450" MinWidth="210" VerticalAlignment="Top" TextWrapping="NoWrap" Name="DisplayInfo"/> </Grid> </UserControl>
背景cs代碼:
using System; using System.IO; using System.Reflection; using System.Runtime.Serialization; using System.Text; namespace Caliburn.Micro.Hello { public class DataContractSerializerViewModel : Screen, IViewModel { private StringBuilder stringBuilder = new StringBuilder(); public string DisplayInfo { get; set; } public DataContractSerializerViewModel() { DisplayName = "DataContractSerializer"; InitData(); stringBuilder.AppendLine("success"); DisplayInfo = stringBuilder.ToString(); } public void InitData() { string fileName = "Programmers.dat"; Stream fs = ; fs = FileReset(fs, fileName); //序列化 DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(Person)); dataContractSerializer.WriteObject(fs, new Person("zzz", "yyy", 555, new lesson() { English = "eee", Chinese = "ccc" })); //反序列化 fs.Position = 0; var p = (Person)dataContractSerializer.ReadObject(fs); //Console.WriteLine($"{p.FirstName},{p.LastName},{p.ID},{p.lesson}"); stringBuilder.AppendLine($"{p.FirstName},{p.LastName},{p.ID},{p.lesson}"); //自定義屬性 Person newPerson = new Person(); Type type = typeof(Person); InformationAttribute informationAttribute; //Querying Class Attributes foreach (Attribute attr in type.GetCustomAttributes(true)) { informationAttribute = attr as InformationAttribute; if ( != informationAttribute) { //Console.WriteLine("Description of AnyClass:\n{0} {1}", // informationAttribute.Description, informationAttribute.DefaultValue); stringBuilder.AppendLine($"Description of AnyClass:\n{informationAttribute.Description} " + $"{informationAttribute.DefaultValue}"); } } //Querying Class-Method Attributes foreach (MethodInfo method in type.GetMethods()) { foreach (Attribute attr in method.GetCustomAttributes(true)) { informationAttribute = attr as InformationAttribute; if ( != informationAttribute) { //Console.WriteLine("Description of {0}:\n{1} ", method.Name, informationAttribute.Description); stringBuilder.AppendLine($"Description of {method.Name}:\n{informationAttribute.Description} "); } } } //Querying Class-Field (only public) Attributes foreach (FieldInfo field in type.GetFields()) { foreach (Attribute attr in field.GetCustomAttributes(true)) { informationAttribute = attr as InformationAttribute; if ( != informationAttribute) { //Console.WriteLine("Description of {0}:\n{1} {2}", field.Name, // informationAttribute.Description, informationAttribute.DefaultValue); stringBuilder.AppendLine($"Description of { field.Name}:\n{informationAttribute.Description} {informationAttribute.DefaultValue}"); //給執行個體對應字段指派 if (field.FieldType == typeof(string)) { newPerson.GetType().GetField(field.Name).SetValue(newPerson, informationAttribute.DefaultValue); } else if (field.FieldType == typeof(Int32)) { newPerson.GetType().GetField(field.Name).SetValue(newPerson, Convert.ToInt32(informationAttribute.DefaultValue)); } } } } } public FileStream FileReset(Stream fStream, string filename) { if (fStream != ) { fStream.Close(); } File.Delete(filename); return new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); } } [DataContract(Name = "Person", Namespace = "http://www.person.com")] public class Person { [DataMember()] [Information(Description = "名稱", DefaultValue = "本山")] public string FirstName; [DataMember] [Information(Description = "性别", DefaultValue = "趙")] public string LastName; [DataMember()] [Information(Description = "序号", DefaultValue = "1")] public int ID; [DataMember()] public lesson lesson; public Person(string newfName, string newLName, int newID, lesson lesson) { FirstName = newfName; LastName = newLName; ID = newID; this.lesson = lesson; } public Person() { } } [DataContract()] public class lesson { [DataMember()] public string English { get; set; } [DataMember()] public string Chinese { get; set; } public override string ToString() { return $"[English] = [{English}], " + $"[Chinese] = [{Chinese}], "; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class InformationAttribute : Attribute { public string Name { get; set; } public string Description { get; set; } public string Unit { get; set; } public string Range { get; set; } public string AvailableValue { get; set; } public string DefaultValue { get; set; } public double Epsilon { get; set; } public byte Precision { get; set; } public string Parameter { get; set; } public uint FixedSize { get; set; } public NodeType NodeType { get; set; } } // // 摘要: // 節點類型(僅用于Dictionary) public enum NodeType { // // 摘要: // The key of dict Key = 0, // // 摘要: // The Value of dict Value = 1 } }
要用DataContractSerializer,首先要引用庫:
System.Runtime.Serialization.dll
需要序列化的類前需要用[DataContract]标注,需要序列化的字段需要用
[DataMember]标注,這裡還定義了一個自定義屬性InformationAttribute,它需要繼承自Attribute,使用方法如下:
這裡通過反射Type type = typeof(Person);擷取類型,通過GetCustomAttributes擷取所有自定義特性,通過GetFields()擷取目前 目前 System.Type 定義的字段,
給執行個體對應字段指派
if (field.FieldType == typeof(string)) { newPerson.GetType().GetField(field.Name).SetValue(newPerson, informationAttribute.DefaultValue); } else if (field.FieldType == typeof(Int32)) { newPerson.GetType().GetField(field.Name).SetValue(newPerson, Convert.ToInt32(informationAttribute.DefaultValue)); }