1. 程式人生 > >C# - 序列化

C# - 序列化

情況 構造函數 解密 name com creat 函數 spa 格式化

序列化Serialize&DeSerialize

序列化就是將C#的類型、對象序列化為字節流,反序列化則是反其道而行,將字節數據反轉成C#類型。序列化的作用主要在於傳輸數據,而字節數據的格式是各種程序都可以通用的傳輸形式。C#類型默認不能被序列化,除非在類型上使用Serializable特性(Serializable在System命名空間中被定義),以表明這是一個可以被序列化的類型。但字符串、集合、數組默認都可以序列化,也即這幾種類型不用為其添加Serializable特性。具體實施序列化操作的類叫做BinaryFormatter,它提供Serialize和Deserialize將對象序列化到流中存儲,BinaryFormatter會自動搜索運用在可序列化類型上的各種序列化(反序列化)特性,根據特性的描述從而對類型進行相應的格式化,這就是為什麽需要序列化對象時,你需要使用一些與序列化有關的特性,下面是常用的幾個序列化特性。

1.Serializable特性

int[] array = { 1,2,3 };

BinaryFormatter format = new BinaryFormatter();
MemoryStream stream = new MemoryStream() ;

format.Serialize(stream, array); //序列化
stream.Position = 0; //此處需要將指針歸位,否則拋錯
int[] newarray=format.Deserialize(stream) as int[]; //反序列化
foreach (var item in newarray)
{
Console
.WriteLine(item);

} using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace ConsoleApp1
{
[Serializable]
public class Animal
{
private string Name = "sam";
public string GetName()
{
return Name;
}
}
class
Program

{
static void Main(string[] args)
{
//序列化
Animal a = new Animal();
BinaryFormatter format = new BinaryFormatter();
MemoryStream stream = new MemoryStream() ;
format.Serialize(stream, a);
stream.Position = 0;
//反序列化
object obj= format.Deserialize(stream);
stream.Position = 0;
Animal newa = obj as Animal;
Console.WriteLine(newa.GetName());

}
}
}

2.NonSerialized特性

序列化會無視private或protected權限修飾符,如果不希望某些成員被序列化,可以在成員上使用NonSerialized特性

[Serializable]
public class Document
{
public string Title;
public string Content;
[NonSerialized]
private long Pass;
}

3.OptionalFieldAttribute特性

如果為可被序列化的類型新增了一個成員,但在未新增成員之前已經序列化這個類型的對象到某個文件,那麽當反序列化這個文件時,BinaryFormatter會因為在查找到類型的新成員與文件保存的序列化數據不匹配從而拋出異常。要避免這樣的情況,可以在新增成員上運用OptionalFieldAttribute特性,BinaryFormatter搜索到新成員時會發現它運用了此特性,這樣,它將自動忽略這個新成員。註意,這個特性在.net framework2.0之前不可用,在這之前的解決辦法可參考C#本質論17章(497頁)。

4.OnSerializing | OnSerialized | OnDeserializing | OnDeserialized特性

這四個特性分別表示:序列化時、序列化完成後、反序列化時、反序列化完成後。也即你可以定義處理方法,並為方法運用這幾個特性。一旦運用了這些特性,你的方法將像事件那般可以被自動觸發,這樣做的優點在於,你可以掌控序列化或反序列化的進行時或完成後的操作。這些特性都會在相應的語義下自動完成對方法的調用,並把方法的邏輯運用在序列化或反序列化後的對象上。比如當一個 屬性被運用了NonSerialized之後,它將被序列化忽視,如果再次將序列化的字符反序列化為對象時,未被序列化的屬性就得不到正確的值,但通過OnDeserialized特性就可以在反序列化完成後將未被序列化的屬性的值運用到反序列化後的對象上。

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace ConsoleApp1
{
[Serializable] //標識為可被序列化/反序列化的特性類
public class Document
{
public string Title;
public string Content;
[NonSerialized]
public long Pass;

[System.Runtime.Serialization.OnSerializing()] //序列化時將執行此方法
public void OnSerializingMethod(System.Runtime.Serialization.StreamingContext context)
{

}

[System.Runtime.Serialization.OnSerialized()] //序列化完成後將執行此方法
public void OnSerializedMethod(System.Runtime.Serialization.StreamingContext context)
{

}

[System.Runtime.Serialization.OnDeserializing()] //反序列化時將執行此方法
public void OnDeserializingMethod(System.Runtime.Serialization.StreamingContext context)
{
}

[System.Runtime.Serialization.OnDeserialized()] //反序列化完成後將執行此方法
public void OnDeserializedMethod(System.Runtime.Serialization.StreamingContext context)
{
Pass = 123;
}
}

class Program
{

static void Main(string[] args)
{
Stream stream;
Document doc = new Document { Title = "xxx", Content = "yyy", Pass = 123 };
string fileName = @"D:\test.txt";
stream = File.Open(fileName, FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, doc);//將Document對象序列化,但Pass未參與序列化
stream.Dispose();
stream = File.Open(fileName, FileMode.Open);
Document doc2 = (Document)formatter.Deserialize(stream); //反序列化完成後將執行OnDeserializedMethod,動態將Pass運用在doc2上
Console.WriteLine(doc2.Title + doc2.Content + doc2.Pass);
}
}
}

5.ISerializable接口

如果你想實現自定義的序列化邏輯,比如內置的序列化功能無法對數據實現加密,而通過使可序列化類型實現ISerializable就可以實現這個效果。此接口提供了GetObjectData方法,還有兩個重要的參數,SerializationInfo(提供序列化信息的對象)、StreamingContext(序列化上下文對象)。SerializationInfo提供AddValue方法將類型的成員添加到字典集合,提供GetString方法獲取某個成員的值。你只需要在GetObjectData裏實現對密碼的加密,在可序列化的類的構造函數裏也接收SerializationInfo和StreamingContext作為參數,這個構造函數用於實現對密碼的解密。

using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace ConsoleApp1
{
[Serializable]
public class XDocument : ISerializable
{
public enum Field { Title, Pass }
public string Title;
public string Pass;

//加密
public static string Encrypt(string data)
{
return "@#$%";
}

//解密
public static string Decrypt(string data)
{
return "123";
}

public XDocument() { }

//在構造函數裏實現對密碼的解密
public XDocument(SerializationInfo info, StreamingContext context)
{
Title = info.GetString(Field.Title.ToString());
Pass = Decrypt(info.GetString(Field.Pass.ToString()));
}

//ISerializable的方法,當對象被序列化時會自動執行這個方法
//在這個方法裏實現加密
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue(Field.Title.ToString(), Title);
info.AddValue(Field.Pass.ToString(), Encrypt(Pass));
}
}

class Program
{

static void Main(string[] args)
{
MemoryStream ms = new MemoryStream();
XDocument doc = new XDocument { Title = "xxx", Pass = "123" };
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, doc);
ms.Position = 0;
object o= formatter.Deserialize(ms);
Console.WriteLine((o as XDocument).Pass);
}
}
}

C# - 學習總目錄

C# - 序列化