【CSharp】序列化

C# 序列化

1 序列化的格式与方式

根据序列化的格式,序列化分为以下三种形式:

  1. 二进制序列化

    指对象序列化之后是二进制形式的。通过 BinaryFormatter 类实现,这个类位于 System.Runtime.Serialization.Formatters.Binary 命名空间下。BinaryFormatter效率很高,能生成非常紧凑的字节流。

    所有成员,甚至只读成员都被执行序列化与反序列化

  2. XML序列化

    指对象序列化之后的结果是XML形式的。通过 XmlSerializer 类实现,这个类位于 System.Xml.Serialization 命名空间下。XML序列化仅将对象的公共字段和属性序列化为XML流,XML序列化不包括类型信息

    方法的参数与返回值也能被序列化

  3. SOAP序列化

    指对象序列化之后的结果符合SOAP协议,也就是说可以通过SOAP协议传输。通过SoapFormatter类实现,这个类位于System.Runtime.Serialization.Formatters.Soap命名空间下。

对序列化进行分类的另一种方式是基于序列化的深度。基于序列化的深度序列化可分为两种形式:

  1. 深序列化

    序列化类的所有public,protectedprivate成员。甚至嵌套类和它们publicprotectedprivate成员也被序列化。

  2. 浅序列化

    .NET框架中,使用二进制格式序列化类的对象,采用深序列化,而使用XML格式序列化类对象为浅序列化。

2 二进制序列化

2.1 一般序列化与反序列化

[Serializable] // 二进制序列化需要以此特性进行标记
public class Person
{
    [NonSerialized] // 表示该字段不参与序列化
    private string 	id 		= "1234567890";
    public  string 	Sno 	{ get; set; }
    public  string 	Name 	{ get; set; }
    public  string 	Sex 	{ get; set; }   
    public  int 	Age 	{ get; set; }

    public string DisplayInfo()
    {
        return $"我的学号是:{Sno}\n我的名字是: {Name}\n我的性别为:{Sex}\n我的年龄:{Age}\n我的ID: {id}";
    }
}

class Program
{
    static void Main(string[] args)
    {
        var me = new Person 
        {
            Sno = "200719",
            Name = "yuananyun",
            Sex = "man",
            Age = 22
        };

        // BinaryFormatter 序列化方式
		using (Stream stream = new FileStream("personInfoBinary.txt", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
		{
			IFormatter formatter = new BinaryFormatter();
			formatter.Serialize(stream, me);
		}
		
		// BinaryFormatter 反序列化方式
		using (Stream destream = new FileStream("personInfoBinary.txt", FileMode.Open, FileAccess.Read, FileShare.Read))
		{
			IFormatter formatter = new BinaryFormatter();
			var stillme = (Person)formatter.Deserialize(destream);
			
			Console.WriteLine(stillme.DisplayInfo());
		}
        
        Console.ReadKey();
    }
}

2.2 自定义序列化与反序列化

[Serializable]
public class TestSimpleObject : System.Runtime.Serialization.ISerializable
{
	public  int member1;
	private string member2;
	[NonSerialized()]
	public  string member3;
	private string member4;

	public TestSimpleObject()
	{
		member1 = 11;
		member2 = "Hello World!";
		member3 = "This is a nonserialized value";
		member4 = null;
	}
	
	protected TestSimpleObject(System.Runtime.Serialization.SerializationInfo info, 
	                           System.Runtime.Serialization.StreamingContext context)
	{
		Console.WriteLine();
		Console.WriteLine("==================================");
		Print();
		member1 = info.GetInt32(nameof(member1)) + 1;
		member2 = info.GetString(nameof(member2)) + "  8888";
		member3 = info.GetString(nameof(member3)) + "  8888";
		member4 = info.GetString(nameof(member4)) + "  8888";
		Console.WriteLine();
		Console.WriteLine(nameof(TestSimpleObject));
		Print();
	}

	public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, 
	                          System.Runtime.Serialization.StreamingContext context)
	{
		Console.WriteLine();
		Console.WriteLine("==================================");
		Print();
		info.AddValue(nameof(member1), member1 - 1);
		info.AddValue(nameof(member2), member2 + "  0000");
		info.AddValue(nameof(member3), member3 + "  0000");
		info.AddValue(nameof(member4), member4 + "  0000");
	}

	public void Print()
	{
		Console.WriteLine("member1 = '{0}'", member1);
		Console.WriteLine("member2 = '{0}'", member2);
		Console.WriteLine("member3 = '{0}'", member3);
		Console.WriteLine("member4 = '{0}'", member4);
	}

	[System.Runtime.Serialization.OnSerializing()]
	internal void OnSerializingMethod(System.Runtime.Serialization.StreamingContext context)
	{
		Console.WriteLine();
		Console.WriteLine("==================================");
		Print();
		member2 = "This value went into the data file during serialization.";
		Console.WriteLine();
		Console.WriteLine(nameof(OnSerializingMethod));
		Print();
		
	}

	[System.Runtime.Serialization.OnSerialized()]
	internal void OnSerializedMethod(System.Runtime.Serialization.StreamingContext context)
	{
		Console.WriteLine();
		Console.WriteLine("==================================");
		Print();
		member2 = "This value was reset after serialization.";
		Console.WriteLine();
		Console.WriteLine(nameof(OnSerializedMethod));
		Print();
		
	}

	[System.Runtime.Serialization.OnDeserializing()]
	internal void OnDeserializingMethod(System.Runtime.Serialization.StreamingContext context)
	{
		Console.WriteLine();
		Console.WriteLine("==================================");
		Console.WriteLine(nameof(OnDeserializingMethod));
		Print();
		Console.WriteLine();
		member3 = "This value was set during deserialization";
		Print();
	}

	[System.Runtime.Serialization.OnDeserialized()]
	internal void OnDeserializedMethod(System.Runtime.Serialization.StreamingContext context)
	{
		Console.WriteLine();
		Console.WriteLine("==================================");
		Console.WriteLine(nameof(OnDeserializedMethod));
		Print();
		Console.WriteLine();
		member1 = member1 + 10000;
		member4 = "This value was set after deserialization.";
		Print();
	}
}

class Program
{
	static void Main(string[] args)
	{
		try
		{
			using (Stream stream = File.Open("DataFile.dat", FileMode.Create))
			{
				TestSimpleObject obj = new TestSimpleObject();
				var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
				formatter.Serialize(stream, obj);
			}
			
			using (Stream stream = File.Open("DataFile.dat", FileMode.Open))
			{
				var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
				var obj = (TestSimpleObject)formatter.Deserialize(stream);
			}
		}
		catch (System.Runtime.Serialization.SerializationException se)
		{
			Console.WriteLine("Failed to serialize. Reason: " + se.Message);
		}
		catch (Exception exc)
		{
			Console.WriteLine("An exception occurred. Reason: " + exc.Message);
		}
	}
}

==================================
member1 = ‘11’
member2 = ‘Hello World!’
member3 = ‘This is a nonserialized value’
member4 = ‘’

OnSerializingMethod
member1 = ‘11’
member2 = ‘This value went into the data file during serialization.’
member3 = ‘This is a nonserialized value’
member4 = ‘’

==================================
member1 = ‘11’
member2 = ‘This value went into the data file during serialization.’
member3 = ‘This is a nonserialized value’
member4 = ‘’

==================================
member1 = ‘11’
member2 = ‘This value went into the data file during serialization.’
member3 = ‘This is a nonserialized value’
member4 = ‘’

OnSerializedMethod
member1 = ‘11’
member2 = ‘This value was reset after serialization.’
member3 = ‘This is a nonserialized value’
member4 = ‘’

==================================
OnDeserializingMethod
member1 = ‘0’
member2 = ‘’
member3 = ‘’
member4 = ‘’

member1 = ‘0’
member2 = ‘’
member3 = ‘This value was set during deserialization’
member4 = ‘’

==================================
member1 = ‘0’
member2 = ‘’
member3 = ‘This value was set during deserialization’
member4 = ‘’

TestSimpleObject
member1 = ‘11’
member2 = ‘This value went into the data file during serialization. 0000 8888’
member3 = ‘This is a nonserialized value 0000 8888’
member4 = ’ 0000 8888’

==================================
OnDeserializedMethod
member1 = ‘11’
member2 = ‘This value went into the data file during serialization. 0000 8888’
member3 = ‘This is a nonserialized value 0000 8888’
member4 = ’ 0000 8888’

member1 = ‘10011’
member2 = ‘This value went into the data file during serialization. 0000 8888’
member3 = ‘This is a nonserialized value 0000 8888’
member4 = ‘This value was set after deserialization.’

3 XML 序列化

XML序列化时使用XmlSerializer类所带来的好处如下:

  • 指定将字段或属性编码为特性还是元素

  • 指定要使用XML命名空间

  • 如果字段或属性不合适,则指定元素或属性的名称。

XML 序列化时使用XmlSerializer类应考虑下列情况。

  • 序列化数据只包含数据本身以及类的结构,不包括类型标识和程序集信息。

  • 只能序列化公共属性和字段。如果需要序列化非公共数据,请使用BinaryFormatter类而不是XML序列化。

  • 类必须有一个默认构造函数。

  • 不能序列化方法。

3.1 一般序列化与反序列化

进行序列化的类的名称作为XML的根元素,公共字段或属性作为XML根元素的子元素。

public class Customer
{
    private int _mID;
    private string _mfirstname;
    private string _mlastname;
    private string _mphone;
    private string _mnotes;

    public int CustomerID
    {
        get { return _mID; }
        set { _mID = value; }
    }
    
    public string FirstName
    {
        get { return _mfirstname; }
        set { _mfirstname = value; }
    }
    
    public string LastName
    {
        get { return _mlastname; }
        set { _mlastname = value; }
    }
    
    public string HomePhone
    {
        get { return _mphone; }
        set { _mphone = value; }
    }
    
    public string Notes
    {
        get { return _mnotes; }
        set { _mnotes = value; }
    }
}
class Program
{
    static void Main(string[] args)
    {
        var custom = new Customer()
        {
            CustomerID = 1234,
            FirstName = "Steven",
            LastName = "Zhou",
            HomePhone = "1234567890",
            Notes = "Test"
        };

        {
            FileStream stream = new FileStream("Customer.xml", FileMode.Create);
            XmlSerializer serializer = new XmlSerializer(typeof(Customer));
            serializer.Serialize(stream, custom);
            stream.Close();
        }

        // 使用浏览器打开
        Process.Start(System.AppDomain.CurrentDomain.BaseDirectory + "Customer.xml");
        
        {
            Customer cus;
            FileStream stream = new FileStream("Customer.xml", FileMode.Open);
            XmlSerializer serializer = new XmlSerializer(typeof(Customer));
            cus = (Customer)serializer.Deserialize(stream);
            stream.Close();
        }

        Console.ReadKey();
    }
}
<?xml version="1.0"?>
<Customer xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <CustomerID>1234</CustomerID>
    <FirstName>Steven</FirstName>
    <LastName>Zhou</LastName>
    <HomePhone>1234567890</HomePhone>
    <Notes>Test</Notes>
</Customer>

3.2 XmlSerializer 类的事件

名称说明
UnknownAttributeXmlSerializer在反序列化过程中遇到未知类型的XML属性(Attribute)时发生
UnknownElementXmlSerializer在反序列化过程中遇到未知类型的XML元素时发生
UnknownNodeXmlSerializer在反序列化过程中遇到未知类型的XML节点时发生
UnreferencedObject在反序列化SOAP编码的XML流的过程中发生,此时XmlSerializer遇到未使用(或未引用)的识别类型
class Program
{
    static void Main(string[] args)
    {
        var custom = new Customer()
        {
            CustomerID = 1234,
            FirstName = "Steven",
            LastName = "Zhou",
            HomePhone = "1234567890",
            Notes = "Test"
        };

        {
            FileStream stream = new FileStream("Customer.xml", FileMode.Create);
            XmlSerializer serializer = new XmlSerializer(typeof(Customer));
            serializer.Serialize(stream, custom);
            stream.Close();
        }

        Process.Start(System.AppDomain.CurrentDomain.BaseDirectory + "Customer.xml");

        {
            Customer cus;
            FileStream stream = new FileStream("Customer.xml", FileMode.Open);
            XmlSerializer serializer = new XmlSerializer(typeof(Customer));
            
            serializer.UnknownAttribute += new XmlAttributeEventHandler(serializer_UnknownAttribute);
            serializer.UnknownElement += new XmlElementEventHandler(serializer_UnknownElement);
            serializer.UnknownNode += new XmlNodeEventHandler(serializer_UnknownNode);
            
            cus = (Customer)serializer.Deserialize(stream);
            stream.Close();
        }

        Console.ReadKey();
    }

    private static void serializer_UnknownNode(object sender, XmlNodeEventArgs e)
    {
        Debug.WriteLine("Unknown Node " + e.Name + " found at Line " + e.LineNumber);
    }

    private static void serializer_UnknownElement(object sender, XmlElementEventArgs e)
    {
        Debug.WriteLine("Unknown Element " + e.Element.Name + " found at Line " + e.LineNumber);
    }

    private static void serializer_UnknownAttribute(object sender, XmlAttributeEventArgs e)
    {
        Debug.WriteLine("Unknown Attribute " + e.Attr.Name + " found at Line " + e.LineNumber);
    }
}

对于复杂类型或嵌套类型:

  1. 序列化和反序列化枚举值,序列化对象的应用程序和反序列化对象的应用程序,都必须考虑定义相同的枚举。
  2. 当序列化对象的属性时,该对象的所有公共程序被序列化。成员名被分配为生成的XML的子元素名。
  3. 在反序列化过程中,XmlSerializer实例化主类,以及所有子类,并分配到各自的属性中。
  4. 序列化数组时,一个XML元素表示数组。单个数组元素构成该元素的子元素。单个数组元素包含在一个元素名和具体决定于数组的数据类型的元素之间。例如,邮件地址可以是string类型的数组,所以单个邮件地址被放在元素之间。
  5. 反序列化时,XmlSerializer 创建一个与序列化元素的数目具有相同数目的数组,然后指定相应的数组元素值。

3.3 自定义序列化与反序列化

XmlSerializer 类在序列化对象时自动将公有成员的名称作为生成的XML元素名称。在许多情况下这是符合我们需要的。然而,有时你可能需要自定义序列化的XML数据,以满足需求。

System.Xml.Serialization命名空间提供了一些属性类来帮助完成上述的自定义序列化。

名称描述
XmlAttributes表示一个特性对象的集合,这些对象控制XmlSerializer如何序列化和反序列化对象
XmlArrayAttribute指定XmlSerializer应将特定的类成员序列化为XML元素数组
XmlArrayItemAttribute指定XmlSerializer可以放置在序列化数组中的派生类型
XmlArrayItemAttributes表示XmlArrayItemAttribute对象的集合
XmlAttributeAttribute指定XmlSerializer应将类成员作为XML属性进行序列化
XmlChoiceIdentifierAttribute指定可以通过使用枚举类进一步消除成员的歧义
XmlElementAttributeXmlSerializer序列化或反序列化包含对象时,指示公共字段或属性标识XML元素
XmlElementAttributes标识XmlElementAttribute的集合,XmlSerializer将其用于它重写序列化类的默认方式
XmlEnumAttribute控制XmlSerializer如何序列化枚举成员
XmlIgnoreAttribute指示XmlSerializerSerializer方法不序列化公共字段或公共属性
XmlIncludeAttribute允许XmlSerializer在它序列化或反序列化对象时识别类型
XmlRootAttribute控制视为XML根元素的属性目标的XML序列化
XmlTextAttribute当序列化或反序列化包含类时,向XmlSerializer指示应将此成员作为XML文本处理
XmlTypeAttribute控制当属性目标由XmlSerializer序列化时生成的XML架构
XmlAnyAttibuteAttribute指定成员(返回XmlAttribute对象的数组的字段)可以包含任何XML属性
XmlAnyElelementAttribute指定成员(返回XmlElementXmlNode对象的数组的字段)可以包含对象,该对象标识在序列化或反序列化的对象中没有相应成员的所有XML元素
XmlAnyElelementAttributes表示XmlAnyElelementAttribute对象的集合
XmlAttributeEventArgsUnknownAttribute事件提供数据
XmlAttributeOverrides允许你在使用XmlSerializer序列化或反序列化对象时重写属性、字段和类特性
XmlElementEventArgsUnknownElement事件提供数据
XmlNamespaceDeclarationsAttribte指定目标属性、参数、返回值或类成员包含于XML文档中所用的命名空间关联的前缀
XmlSerializer将对象序列化到XML文档中和从XML文档中反序列化对象。XmlSerialzier使你得以控制如何将对象编码到XML中
XmlSerilizerNamespaces包含XmlSerializer用于在XM文档实例中生成限定名的XML命名空间和前缀
XmlTypeMapping包含从一种类型到另一种类型的映射
public enum CustomerType
{ 
    [XmlEnumAttribute(Name="Personal Customer")] 
    Personal, 
    [XmlEnumAttribute(Name="Company Customer")] 
    Company
}
public class Address
{
    private string _mstreet;
    private string _mcity;
    private string _mstate;
    private string _mcountry;
    private string _mpostalcode;

    public string Street
    {
        get { return _mstreet; }
        set { _mstreet = value; }
    }
    
    public string City
    {
        get { return _mcity; }
        set { _mcity = value; }
    }
    
    public string State
    {
        get { return _mstate; }
        set { _mstate = value; }
    }
    
    public string Country
    {
        get { return _mcountry; }
        set { _mcountry = value; }
    }
    
    public string PostalCode
    {
        get { return _mpostalcode; }
        set { _mpostalcode = value; }
    }
}
class Program
{
    static void Main(string[] args)
    {
        var custom = new Customer()
        {
            CustomerID = 1234,
            FirstName = "Steven",
            LastName = "Zhou",
            HomePhone = "1234567890",
            Notes = "Test",
            Emails = new string[] 
            { 
                "abc@gmail.com",
                "bcd@gmail.com",
                "cde@gmail.com",
                "def@gmail.com"
            },
            Type = CustomerType.Company
        };

        {
            FileStream stream = new FileStream("Customer.xml", FileMode.Create);
            XmlSerializer serializer = new XmlSerializer(typeof(Customer));
            serializer.Serialize(stream, custom);
            stream.Close();
        }

        Process.Start(System.AppDomain.CurrentDomain.BaseDirectory + "Customer.xml");

        {
            Customer cus;
            FileStream stream = new FileStream("Customer.xml", FileMode.Open);
            XmlSerializer serializer = new XmlSerializer(typeof(Customer));
            cus = (Customer)serializer.Deserialize(stream);
            stream.Close();
        }

        Console.ReadKey();
    }
}
// 改变XML文档的根元素名
[XmlRootAttribute(ElementName="CustomerInfo")]
public class Customer
{
    private int _mID;
    private string _mfirstname;
    private string _mlastname;
    private string _mphone;
    private string _mnotes;
    private string[] _memails;
    private CustomerType _mtype;
    private Address _maddress = new Address();

    // 表示将把类的共有属性序列化为XML属性,而不是XML元素
    [XmlAttributeAttribute(AttributeName="CustomerID")]
    public int CustomerID
    {
        get { return _mID; }
        set { _mID = value; }
    }
    
    [XmlElementAttribute(ElementName="FName")]
    public string FirstName
    {
        get { return _mfirstname; }
        set { _mfirstname = value; }
    }
    
    [XmlElementAttribute(ElementName = "LName")]
    public string LastName
    {
        get { return _mlastname; }
        set { _mlastname = value; }
    }
    
    // 忽略该公开属性的序列化
    [XmlIgnoreAttribute] 
    public string HomePhone
    {
        get { return _mphone; }
        set { _mphone = value; }
    }
    
    [XmlElementAttribute(ElementName = "Remarks")]
    public string Notes
    {
        get { return _mnotes; }
        set { _mnotes = value; }
    }
    
    [XmlElementAttribute(ElementName = "CustomerType")]
    public CustomerType Type
    {
        get { return _mtype; }
        set { _mtype = value; }
    }
    
    // 指定序列化数组时,元素的名称,元素项的名称
    [XmlArrayAttribute(ElementName="EmailAddresses")]
    [XmlArrayItemAttribute(ElementName="Email")]
    public string[] Emails
    {
        get { return _memails; }
        set { _memails = value; }
    }
    
    // 如果该属性为null,XmlAttribte仍然为它设置一个空XML元素
    [XmlElementAttribute(IsNullable=true)] 
    public Address Address
    {
        get { return _maddress; }
        set { _maddress = value; }
    }
}
<?xml version="1.0"?>
<CustomerInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
              xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
              CustomerID="1234">
  <FName>Steven</FName>
  <LName>Zhou</LName>
  <Remarks>Test</Remarks>
  <CustomerType>Company Customer</CustomerType>
  <EmailAddresses>
    <Email>abc@gmail.com</Email>
    <Email>bcd@gmail.com</Email>
    <Email>cde@gmail.com</Email>
    <Email>def@gmail.com</Email>
  </EmailAddresses>
  <Address />
</CustomerInfo>

3.4 XmlSerializerHelper

/// <summary>
/// 指定邮件地址的类型 
/// </summary>
public enum EmailDestination
{
    Home = 0,
    Business = 1,
    Other = 2,
}
//表明该类能被序列化
[Serializable] 
public class EmailAddress
{
    public EmailAddress()
    {
    }
        
    [XmlAttributeAttribute] // 指名这个公有字段被序列化时,将作为XML的属性出现
    public string Address = null;

    [XmlAttributeAttribute] // 指名这个公有字段被序列化时,将作为XML的属性出现
    public EmailDestination Destination = EmailDestination.Home;
}
//设置'Customer'作为任何序列化的XML文档的根元素名
[XmlRootAttribute("Customer", Namespace = "", IsNullable = false)]
public class Customer
{
    #region Variables
    private Bitmap picture;

    [XmlAttributeAttribute(DataType="date")] //指名这个公有字段被序列化时,作为根节点的属性出现
    public System.DateTime DateTimeValue;

    public int CustomerID;
    public string CustomerName;
    public int Age;

    [XmlIgnoreAttribute()] //序列化时忽略这个字段 
    public bool CustomerPaid;

    //序列化名为'Hobbies'的ArrayList数组,并将'Hobby'作为XML的元素名
    [XmlArrayAttribute("Hobbies"), XmlArrayItemAttribute("Hobby", typeof(string))]
    public System.Collections.ArrayList Hobbies = new System.Collections.ArrayList();

    //序列化名为'EmailAddresses'的ArrayList数组,并将'EmailAddress'作为XML的元素名
    [XmlArrayAttribute("EmailAddresses"), XmlArrayItemAttribute("EmailAddress", typeof(EmailAddress))]
    public System.Collections.ArrayList EmailAddresses = new System.Collections.ArrayList();
        
    #endregion

    #region Constructor

    public Customer()
    {
    }
    #endregion

    #region Properties

    [XmlIgnoreAttribute()]//序列化时忽略这个共有属性,因为在序列化时'PictureByteArray'共有属性替代了它
    public Bitmap Picture
    {
        get { return picture; }
        set { picture = value; }
    }

    [XmlElementAttribute("Picture")]//序列化这个共有属性,将其元素名设定为'Picture'
    public byte[] PictureByteArray
    {
        get
        {
            if (picture != null)
            {
                // 由于使用System.Xml.Serialization.XmlSerializer类不能自动序列化/反序列化位图
                // 因而Bitmap对象作为一个字节数组保存到XML文件中,当XML文件被加载时,转换成位图。
                // 使用System.ComponentModel.TypeConverterBitmap实现从一个Bitmap对象转换为字节
                // 数组。使用System.IO.MemoryStream实现从一个字节数组转换回Bitmap对象。
                TypeConverter BitmapConverter = TypeDescriptor.GetConverter(picture.GetType());
                return (byte[])BitmapConverter.ConvertTo(picture, typeof(byte[]));
            }
            else
            {
                return null;
            }
        }
        
        set
        {
            if (value != null)
            {
                picture = new Bitmap(new MemoryStream(value));
            }
            else
            {
                picture = null;
            }
        }
    }
    #endregion
}
/// <summary>
/// 序列化格式类型
/// </summary>
public enum SerializedFormat
{
    Binary, //二进制序列化格式
    Document //XML序列化格式
}
//将该类定义为'static',则可以直接调用类中的方法函数,而不需实例化该类, <T>表明该类是范型类.
public static class ObjectXMLSerializer<T> where T : class //指定参数T必须是类 
{
    #region Load methods

    /// <summary>
    /// 加载一个XML文档(文档为Document格式)对象
    /// </summary>
    /// <example>
    /// <code>
    /// serializableObject = ObjectXMLSerializer&lt;SerializableObject&gt;.Load(@"C:\XMLObjects.xml");
    /// </code>
    /// </example>
    /// <param name="path">被加载的文件的路径</param>
    /// <returns>返回一个T类类型的对象</returns>
    public static T Load(string path)
    {
        T serializableObject = LoadFromDocumentFormat(null, path, null);
        return serializableObject;
    }

    /// <summary>
    /// 加载一个XML文档(文档为使用指定的格式序列化)对象
    /// </summary>
    /// <example>
    /// <code>
    /// serializableObject = ObjectXMLSerializer&lt;SerializableObject&gt;.Load(@"C:\XMLObjects.xml", SerializedFormat.Binary);
    /// </code>
    /// </example>		
    /// <param name="path">被加载的文件的路径</param>
    /// <param name="serializedFormat">XML的序列化格式</param>
    /// <returns>返回一个用指定的格式序列化的XML文件的对象</returns>
    public static T Load(string path, SerializedFormat serializedFormat)
    {
        T serializableObject = null;

        switch (serializedFormat)
        {
            case SerializedFormat.Binary:
                serializableObject = LoadFromBinaryFormat(path, null);
                break;

            case SerializedFormat.Document:
            default:
                serializableObject = LoadFromDocumentFormat(null, path, null);
                break;
        }

        return serializableObject;
    }

    /// <summary>
    /// 加载一个XML文档(文档为Document格式)对象,并且支持额外的数据类型以使反序列化时自定义类型能包含在对象中
    /// </summary>
    /// <example>
    /// <code>
    /// serializableObject = ObjectXMLSerializer&lt;SerializableObject&gt;.Load(@"C:\XMLObjects.xml", new Type[] { typeof(MyCustomType) });
    /// </code>
    /// </example>
    /// <param name="path">被加载的文件的路径</param>
    /// <param name="extraTypes">额外的数据类型以使反序列化时自定义类型能包含在对象中</param>
    /// <returns>返回一个XML文件对象</returns>
    public static T Load(string path, System.Type[] extraTypes)
    {
        T serializableObject = LoadFromDocumentFormat(extraTypes, path, null);
        return serializableObject;
    }

    /// <summary>
    /// 加载一个位于指定的隔离储存区中XML文档(文档为Document格式)对象
    /// </summary>
    /// <example>
    /// <code>
    /// serializableObject = ObjectXMLSerializer&lt;SerializableObject&gt;.Load("XMLObjects.xml", IsolatedStorageFile.GetUserStoreForAssembly());
    /// </code>
    /// </example>
    /// <param name="fileName">位于用于装载对象的指定的隔离储存区中的文件名</param>
    /// <param name="isolatedStorageDirectory">包含XML文件的隔离储存区目录</param>
    /// <returns>返回一个位于指定的隔离储存区中的XML文件对象</returns>
    public static T Load(string fileName, IsolatedStorageFile isolatedStorageDirectory)
    {
        T serializableObject = LoadFromDocumentFormat(null, fileName, isolatedStorageDirectory);
        return serializableObject;
    }

    /// <summary>
    /// 加载一个位于指定的隔离储存区中的XML文档(文档为使用指定的格式序列化)对象
    /// </summary>
    /// <example>
    /// <code>
    /// serializableObject = ObjectXMLSerializer&lt;SerializableObject&gt;.Load("XMLObjects.xml", IsolatedStorageFile.GetUserStoreForAssembly(), SerializedFormat.Binary);
    /// </code>
    /// </example>		
    /// <param name="fileName">位于用于装载对象的隔离储存区中的文件名</param>
    /// <param name="isolatedStorageDirectory">包含XML文件的隔离储存区目录</param>
    /// <param name="serializedFormat">XML的序列化格式</param>        
    /// <returns>返回一个位于指定的隔离储存区中的XML文件对象</returns>
    public static T Load(string fileName, IsolatedStorageFile isolatedStorageDirectory, SerializedFormat serializedFormat)
    {
        T serializableObject = null;

        switch (serializedFormat)
        {
            case SerializedFormat.Binary:
                serializableObject = LoadFromBinaryFormat(fileName, isolatedStorageDirectory);
                break;

            case SerializedFormat.Document:
            default:
                serializableObject = LoadFromDocumentFormat(null, fileName, isolatedStorageDirectory);
                break;
        }

        return serializableObject;
    }

    /// <summary>
    /// 加载一个位于指定的隔离储存区中XML文档(文档为Document格式)对象并且支持额外的数据类型以使反序列化时自定义类型能包含在对象中
    /// </summary>
    /// <example>
    /// <code>
    /// serializableObject = ObjectXMLSerializer&lt;SerializableObject&gt;.Load("XMLObjects.xml", IsolatedStorageFile.GetUserStoreForAssembly(), new Type[] { typeof(MyCustomType) });
    /// </code>
    /// </example>		
    /// <param name="fileName">位于用于装载对象的隔离储存区中的文件名</param>
    /// <param name="isolatedStorageDirectory">包含XML文件的隔离储存区目录</param>
    /// <param name="extraTypes">额外的数据类型以使反序列化时自定义类型能包含在对象中</param>
    /// <returns>返回一个位于指定的隔离储存区中的XML文件对象</returns>
    public static T Load(string fileName, IsolatedStorageFile isolatedStorageDirectory, System.Type[] extraTypes)
    {
        T serializableObject = LoadFromDocumentFormat(null, fileName, isolatedStorageDirectory);
        return serializableObject;
    }

    #endregion

    #region Private Methods

    private static FileStream CreateFileStream(IsolatedStorageFile isolatedStorageFolder, string path)
    {
        FileStream fileStream = null;

        if (isolatedStorageFolder == null)
            fileStream = new FileStream(path, FileMode.OpenOrCreate);
        else
            fileStream = new IsolatedStorageFileStream(path, FileMode.OpenOrCreate, isolatedStorageFolder);

        return fileStream;
    }

    private static T LoadFromBinaryFormat(string path, IsolatedStorageFile isolatedStorageFolder)
    {
        T serializableObject = null;

        using (FileStream fileStream = CreateFileStream(isolatedStorageFolder, path))
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            serializableObject = binaryFormatter.Deserialize(fileStream) as T;
        }

        return serializableObject;
    }

    private static T LoadFromDocumentFormat(System.Type[] extraTypes, string path, IsolatedStorageFile isolatedStorageFolder)
    {
        T serializableObject = null;

        using (TextReader textReader = CreateTextReader(isolatedStorageFolder, path))
        {
            XmlSerializer xmlSerializer = CreateXmlSerializer(extraTypes);
            serializableObject = xmlSerializer.Deserialize(textReader) as T;

        }

        return serializableObject;
    }

    private static TextReader CreateTextReader(IsolatedStorageFile isolatedStorageFolder, string path)
    {
        TextReader textReader = null;

        if (isolatedStorageFolder == null)
            textReader = new StreamReader(path);
        else
            textReader = new StreamReader(new IsolatedStorageFileStream(path, FileMode.Open, isolatedStorageFolder));

        return textReader;
    }

    private static TextWriter CreateTextWriter(IsolatedStorageFile isolatedStorageFolder, string path)
    {
        TextWriter textWriter = null;

        if (isolatedStorageFolder == null)
            textWriter = new StreamWriter(path);
        else
            textWriter = new StreamWriter(new IsolatedStorageFileStream(path, FileMode.OpenOrCreate, isolatedStorageFolder));

        return textWriter;
    }

    private static XmlSerializer CreateXmlSerializer(System.Type[] extraTypes)
    {
        Type ObjectType = typeof(T);

        XmlSerializer xmlSerializer = null;

        if (extraTypes != null)
            xmlSerializer = new XmlSerializer(ObjectType, extraTypes);
        else
            xmlSerializer = new XmlSerializer(ObjectType);

        return xmlSerializer;
    }

    private static void SaveToDocumentFormat(T serializableObject, System.Type[] extraTypes, string path, IsolatedStorageFile isolatedStorageFolder)
    {
        using (TextWriter textWriter = CreateTextWriter(isolatedStorageFolder, path))
        {
            XmlSerializer xmlSerializer = CreateXmlSerializer(extraTypes);
            xmlSerializer.Serialize(textWriter, serializableObject);
        }
    }

    private static void SaveToBinaryFormat(T serializableObject, string path, IsolatedStorageFile isolatedStorageFolder)
    {
        using (FileStream fileStream = CreateFileStream(isolatedStorageFolder, path))
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(fileStream, serializableObject);
        }
    }

    #endregion

    #region Save methods

    /// <summary>
    /// 存储一个对象到XML文档(文档为Document格式)中
    /// </summary>
    /// <example>
    /// <code>        
    /// SerializableObject serializableObject = new SerializableObject();
    /// 
    /// ObjectXMLSerializer&lt;SerializableObject&gt;.Save(serializableObject, @"C:\XMLObjects.xml");
    /// </code>
    /// </example>
    /// <param name="serializableObject">存储到文档中的序列化对象</param>
    /// <param name="path">存储序列化对象的文件的路径</param>
    public static void Save(T serializableObject, string path)
    {
        SaveToDocumentFormat(serializableObject, null, path, null);
    }

    /// <summary>
    /// 存储一个对象到XML文档(文档为指定的序列化格式)中
    /// </summary>
    /// <example>
    /// <code>
    /// SerializableObject serializableObject = new SerializableObject();
    /// 
    /// ObjectXMLSerializer&lt;SerializableObject&gt;.Save(serializableObject, @"C:\XMLObjects.xml", SerializedFormat.Binary);
    /// </code>
    /// </example>
    /// <param name="serializableObject">存储到文档中的序列化对象</param>
    /// <param name="path">存储序列化对象的文件的路径</param>
    /// <param name="serializedFormat">XML的序列化格式</param>
    public static void Save(T serializableObject, string path, SerializedFormat serializedFormat)
    {
        switch (serializedFormat)
        {
            case SerializedFormat.Binary:
                SaveToBinaryFormat(serializableObject, path, null);
                break;

            case SerializedFormat.Document:
            default:
                SaveToDocumentFormat(serializableObject, null, path, null);
                break;
        }
    }

    /// <summary>
    /// 存储一个对象到XML文档(文档为Document格式)中,并且支持额外的数据类型以使序列化时自定义类型能包含在对象中
    /// </summary>
    /// <example>
    /// <code>        
    /// SerializableObject serializableObject = new SerializableObject();
    /// 
    /// ObjectXMLSerializer&lt;SerializableObject&gt;.Save(serializableObject, @"C:\XMLObjects.xml", new Type[] { typeof(MyCustomType) });
    /// </code>
    /// </example>
    /// <param name="serializableObject">存储到文档中的序列化对象</param>
    /// <param name="path">存储序列化对象的文件的路径</param>
    /// <param name="extraTypes">额外的数据类型以使序列化时自定义类型能包含在对象中</param>
    public static void Save(T serializableObject, string path, System.Type[] extraTypes)
    {
        SaveToDocumentFormat(serializableObject, extraTypes, path, null);
    }

    /// <summary>
    /// 存储一个对象到位于指定的隔离储存区中的XML文档(文档为Document格式)中
    /// </summary>
    /// <example>
    /// <code>        
    /// SerializableObject serializableObject = new SerializableObject();
    /// 
    /// ObjectXMLSerializer&lt;SerializableObject&gt;.Save(serializableObject, "XMLObjects.xml", IsolatedStorageFile.GetUserStoreForAssembly());
    /// </code>
    /// </example>
    /// <param name="serializableObject">存储到文档中的序列化对象</param>
    /// <param name="fileName">位于指定的隔离储存区中的用于存储对象的文件名</param>
    /// <param name="isolatedStorageDirectory">包含XML文件的隔离储存区目录</param>
    public static void Save(T serializableObject, string fileName, IsolatedStorageFile isolatedStorageDirectory)
    {
        SaveToDocumentFormat(serializableObject, null, fileName, isolatedStorageDirectory);
    }

    /// <summary>
    /// 存储一个对象到位于指定的隔离储存区中的XML文档(文档为指定的序列化格式)中
    /// </summary>
    /// <example>
    /// <code>        
    /// SerializableObject serializableObject = new SerializableObject();
    /// 
    /// ObjectXMLSerializer&lt;SerializableObject&gt;.Save(serializableObject, "XMLObjects.xml", IsolatedStorageFile.GetUserStoreForAssembly(), SerializedFormat.Binary);
    /// </code>
    /// </example>
    /// <param name="serializableObject">存储到文档中的序列化对象</param>
    /// <param name="fileName">位于指定的隔离储存区中的用于存储对象的文件名</param>
    /// <param name="isolatedStorageDirectory">包含XML文件的隔离储存区目录</param>
    /// <param name="serializedFormat">XML的序列化格式</param>        
    public static void Save(T serializableObject, string fileName, IsolatedStorageFile isolatedStorageDirectory, SerializedFormat serializedFormat)
    {
        switch (serializedFormat)
        {
            case SerializedFormat.Binary:
                SaveToBinaryFormat(serializableObject, fileName, isolatedStorageDirectory);
                break;

            case SerializedFormat.Document:
            default:
                SaveToDocumentFormat(serializableObject, null, fileName, isolatedStorageDirectory);
                break;
        }
    }

    /// <summary>
    /// 存储一个对象到位于指定的隔离储存区中的XML文档(文档为Document格式)中,并且支持额外的数据类型以使序列化时自定义类型能包含在对象中
    /// </summary>
    /// <example>
    /// <code>
    /// SerializableObject serializableObject = new SerializableObject();
    /// 
    /// ObjectXMLSerializer&lt;SerializableObject&gt;.Save(serializableObject, "XMLObjects.xml", IsolatedStorageFile.GetUserStoreForAssembly(), new Type[] { typeof(MyCustomType) });
    /// </code>
    /// </example>		
    /// <param name="serializableObject">存储到文档中的序列化对象</param>
    /// <param name="fileName">位于指定的隔离储存区中的用于存储对象的文件名</param>
    /// <param name="isolatedStorageDirectory">包含XML文件的隔离储存区目录</param>
    /// <param name="extraTypes">额外的数据类型以使序列化时自定义类型能包含在对象中</param>
    public static void Save(T serializableObject, string fileName, IsolatedStorageFile isolatedStorageDirectory, System.Type[] extraTypes)
    {
        SaveToDocumentFormat(serializableObject, null, fileName, isolatedStorageDirectory);
    }

    #endregion
}

4 SOAP序列化

SOAP(Simple Object Access Protocol),简单对象访问协议,是在分散或分布式的环境中交换信息的简单的协议,是一个基于XML的协议,是Web服务的一个工业标准。虽然SOAP被广泛用于Web服务,但也可以使用它作为一个对象序列化的编码格式。

使用SOAP格式序列化对象时,就必须用Serializable特性标记类。只有这样,类才能被序列化。SoapFormatter 类驻留在System.Runtime.Serialization.Formatters.Soap命名空间中。

4.1 一般序列化与反序列化

[Serializable]
public class Customer
{
    private int _mID;
    private string _mfirstname;
    private string _mlastname;
    private string _mphone;
    private string _mnotes;

    public int CustomerID
    {
        get { return _mID; }
        set { _mID = value; }
    }

    public string FirstName
    {
        get { return _mfirstname; }
        set { _mfirstname = value; }
    }

    public string LastName
    {
        get { return _mlastname; }
        set { _mlastname = value; }
    }

    public string HomePhone
    {
        get { return _mphone; }
        set { _mphone = value; }
    }

    public string Notes
    {
        get { return _mnotes; }
        set { _mnotes = value; }
    }
}

序列化

public void Serialization(Customer cus, string fileName)
{
    FileStream stream = new FileStream(fileName, FileMode.Create);
    SoapFormatter formatter = new SoapFormatter();
    formatter.Serialize(stream, cus);
}

反序列化

public Customer Deserialization(string fileName)
{
    Customer cus;
    FileStream stream = new FileStream(fileName, FileMode.Open);
    SoapFormatter formatter = new SoapFormatter();
    cus = (Customer)formatter.Deserialize(stream);
    stream.Close();
    
    return cus;
}

4.2 自定义序列化与反序列化

实现自定义SOAP序列化的方式有两种:

  • 实现ISerializable接口
  • 使用特定的序列化和反序列化属性

从.NET 2.0开始第一种方式就被第二种方式所取代,因此这里采用第二种方式实现自定义SOAP序列化。

假如相对普通用户保护你的序列化的XML数据。比如你想在序列化数据时,对数据实现Base64编码,使普通读者不能阅读的内容。而在反序列化时,这些数据需要实现Base64编码模式的解码。在这种情况下,自定义序列化属性将派上用场。

[Serializable]
public class Customer
{
    #region Variables

    private int _mID;
    private string _mfirstname;
    private string _mlastname;
    private string _mphone;
    private string _mnotes;
    #endregion

    #region Properties

    public int CustomerID
    {
        get { return _mID; }
        set { _mID = value; }
    }
    public string FirstName
    {
        get { return _mfirstname; }
        set { _mfirstname = value; }
    }
    public string LastName
    {
        get { return _mlastname; }
        set { _mlastname = value; }
    }
    public string HomePhone
    {
        get { return _mphone; }
        set { _mphone = value; }
    }
    public string Notes
    {
        get { return _mnotes; }
        set { _mnotes = value; }
    }
    #endregion

    #region Methods
    private string Encode(string str)
    {
        // 将数据转化为Base64格式
        byte[] data = ASCIIEncoding.ASCII.GetBytes(str);
        return Convert.ToBase64String(data);
    }
    
    private string Decode(string str)
    {
        // 将Base64格式字符串转换为普通字符串
        byte[] data = Convert.FromBase64String(str);
        return ASCIIEncoding.ASCII.GetString(data);
    }
    
    [OnSerializingAttribute]
    public void OnSerializing(StreamingContext context)
    {
        _mfirstname = Encode(_mfirstname);
        _mlastname = Encode(_mlastname);
        _mphone = Encode(_mphone);
        _mnotes = Encode(_mnotes);
    }
    
    [OnSerializedAttribute]
    public void OnSerialized(StreamingContext context)
    {
        _mfirstname = Decode(_mfirstname);
        _mlastname = Decode(_mlastname);
        _mphone = Decode(_mphone);
        _mnotes = Decode(_mnotes);
    }

    [OnDeserializingAttribute]
    public void OnDeserializing(StreamingContext context)
    {
        //no code here
    }

    [OnDeserializedAttribute]
    public void OnDeserialized(StreamingContext context)
    {
        _mfirstname = Decode(_mfirstname);
        _mlastname = Decode(_mlastname);
        _mphone = Decode(_mphone);
        _mnotes = Decode(_mnotes);
    }
    #endregion
}

四种方法分别用四种特性加以标记。这些特性允许你通过使用前置和后置的方法自定义序列化和反序列化过程。

  • OnSerializingAttribute

    在数据进行序列化前被调用

  • OnSerializedAttribute

    在序列化数据完成后被调用

  • OnDeserializingAttribute

    在数据反序列化前被调用

  • OnDeserializedAttribute

    在数据反序列化后被调用

序列化

public void Serialization(Customer cus, string fileName)
{
    FileStream stream = new FileStream(fileName, FileMode.Create);
    SoapFormatter formatter = new SoapFormatter();
    formatter.Serialize(stream, cus);
}

反序列化

public Customer Deserialization(string fileName)
{
    Customer cus;
    FileStream stream = new FileStream(fileName, FileMode.Open);
    SoapFormatter formatter = new SoapFormatter();
    cus = (Customer)formatter.Deserialize(stream);
    stream.Close();
    
    return cus;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Unity中的序列(Serialization)是指将对象转换为字节流的过程,而反序列(Deserialization)则是将字节流转换为对象的过程。Unity提供了一些机制来实现对象的序列和反序列。 Unity的序列机制主要用于保存和加载游戏对象的状态,或者在网络传输中传递对象。以下是一些常见的序列和反序列方法: 1. Unity的内置序列:Unity提供了内置的序列机制,使得你可以将脚本中的变量标记为可序列。通过在变量前面添加 `[SerializeField]` 属性,可以将该变量标记为可序列。例如: ```csharp [SerializeField] private int score; ``` 2. XML 和 JSON 序列:Unity还支持使用XML或JSON格式进行序列和反序列。你可以使用 `System.Xml.Serialization` 命名空间下的类来进行XML的序列和反序列,或者使用JsonUtility类来进行JSON的序列和反序列。 ```csharp // XML序列和反序列示例 using System.Xml.Serialization; // 序列为XML XmlSerializer serializer = new XmlSerializer(typeof(MyClass)); using (StreamWriter writer = new StreamWriter("data.xml")) { serializer.Serialize(writer, myObject); } // 从XML反序列 using (StreamReader reader = new StreamReader("data.xml")) { MyClass myObject = (MyClass)serializer.Deserialize(reader); } // JSON序列和反序列示例 using UnityEngine; using UnityEngine.Networking; // 序列为JSON string json = JsonUtility.ToJson(myObject); // 从JSON反序列 MyClass myObject = JsonUtility.FromJson<MyClass>(json); ``` 3. 二进制序列:如果需要更高效的序列和反序列操作,可以使用二进制格式。Unity提供了BinaryFormatter类来进行二进制的序列和反序列。 ```csharp // 二进制序列和反序列示例 using System.Runtime.Serialization.Formatters.Binary; // 序列为二进制 BinaryFormatter formatter = new BinaryFormatter(); using (FileStream stream = new FileStream("data.bin", FileMode.Create)) { formatter.Serialize(stream, myObject); } // 从二进制反序列 using (FileStream stream = new FileStream("data.bin", FileMode.Open)) { MyClass myObject = (MyClass)formatter.Deserialize(stream); } ``` 这些是Unity中常用的序列和反序列方法,你可以根据具体的需求选择适合的方法来实现对象的序列和反序列

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhy29563

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值