比如有一個Person類,儲存人的名字。(但是這個類在後續的開發中被另一個類Person_ver2代替):
//+ using System.Runtime.Serialization
[Serializable, Obsolete("請使用Person_ver2類型")]
class Person : ISerializable
{
public string Name { get; set; }
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("name", Name);
}
/* 還原序列化代碼省略 */
}
Person_ver2把Person的Name屬性按照姓和名,分別儲存:
[Serializable]
class Person_ver2 : ISerializable
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
問題就是怎樣把已經序列化好的Person類對象資料在還原序列化過程中正確轉換成Person_ver2類型?
SerializationBinder類(在System.Runtime.Serialization命名空間內)可以協助我們達到這個要求。
通過改寫SerializationBinder的BindToType方法,我們可以在還原序列化過程中重新引導執行還原序列化操作的類型。類型的標識是應用程式集名稱和類型的完整路徑。當然對應還原序列化類型要有處理其他被引導類型資料的操作。
因此Person_ver2類型應該這樣定義:
//新版Person類:Person_ver2
[Serializable]
class Person_ver2 : ISerializable
{
public string FirstName { get; set; }
public string LastName { get; set; }
//還原序列化
protected Person_ver2(SerializationInfo info, StreamingContext context)
{
try
{
FirstName = info.GetString("firstName");
LastName = info.GetString("lastName");
}
catch (SerializationException)
{
//如果有錯誤(不存在firstName和lastName在SerializationInfo中)
//則說明是Person類引導過來的還原序列化對象資料
Console.WriteLine("從Person類型轉換至Person_ver2");
//將Person類還原序列化並轉換成本類型
var names = info.GetString("name").Split(' ');
FirstName = names[0];
LastName = names[1];
}
}
public override string ToString()
{
return String.Format("姓名:{0} - {1}", FirstName, LastName);
}
//序列化代碼省略
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotImplementedException();
}
}
接著在SerializationBinder的執行上,通過應用程式集名稱來類型名稱來判斷是否是Person類型,如果是返回Person_ver2的類型標識。
//+ using System.Runtime.Serialization
//SerializationBinder的執行類
class ConversionBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
//篩選Person類型
//判斷是否是Person類型,如果是返回Person_ver2
var curAssName = typeof(Program).Assembly.FullName;
var person1 = typeof(Person).FullName;
string finalType = typeName;
if (assemblyName == curAssName && typeName == person1)
finalType = typeof(Person_ver2).FullName;
return Type.GetType(finalType + "," + assemblyName);
}
}
最後就可以進行轉換了,注意SerializationBinder通過IFormatter的Binder屬性設定。
主函數代碼:
//+ using System.Runtime.Serialization
//+ using System.Runtime.Serialization.Formatters.Binary
//+ using System.IO;
//建立Person對象
var p1 = new Person() { Name = "Kevin Martin" };
using (var ms = new MemoryStream())
{
var bf = new BinaryFormatter();
//設定自訂的SerializationBinder對象
bf.Binder = new ConversionBinder();
//序列化Person
bf.Serialize(ms, p1);
ms.Seek(0, SeekOrigin.Begin);
//把Person還原序列化成Person_ver2
var p2 = (Person_ver2)bf.Deserialize(ms);
//輸出Person_ver2
Console.WriteLine(p2.ToString());
}
輸出:
從Person類型轉換至Person_ver2
姓名:Kevin – Martin
OK,還原序列化Person對象成功調用了Person_ver2的還原序列化建構函式,並將Person轉換成Person_ver2對象。