一些陷入向後相容的問題
這個小例子說明了如果你沒有提前注意這個問題,你如何在程式中失去向後相容性。以及如何更好地控制序列化過程
首先,我們將編寫該程式的第一個版本的示例:
版本 1
[Serializable]
class Data
{
[OptionalField]
private int _version;
public int Version
{
get { return _version; }
set { _version = value; }
}
}
而現在,讓我們假設在該程式的第二個版本中新增了一個新類。我們需要將它儲存在一個陣列中。
現在程式碼看起來像這樣:
版本 2
[Serializable]
class NewItem
{
[OptionalField]
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
[Serializable]
class Data
{
[OptionalField]
private int _version;
public int Version
{
get { return _version; }
set { _version = value; }
}
[OptionalField]
private List<NewItem> _newItems;
public List<NewItem> NewItems
{
get { return _newItems; }
set { _newItems = value; }
}
}
以及用於序列化和反序列化的程式碼
private static byte[] SerializeData(object obj)
{
var binaryFormatter = new BinaryFormatter();
using (var memoryStream = new MemoryStream())
{
binaryFormatter.Serialize(memoryStream, obj);
return memoryStream.ToArray();
}
}
private static object DeserializeData(byte[] bytes)
{
var binaryFormatter = new BinaryFormatter();
using (var memoryStream = new MemoryStream(bytes))
return binaryFormatter.Deserialize(memoryStream);
}
那麼,當你在 v2 程式中序列化資料並嘗試在 v1 程式中反序列化時會發生什麼?
你得到一個例外:
System.Runtime.Serialization.SerializationException was unhandled
Message=The ObjectManager found an invalid number of fixups. This usually indicates a problem in the Formatter.Source=mscorlib
StackTrace:
at System.Runtime.Serialization.ObjectManager.DoFixups()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
at Microsoft.Samples.TestV1.Main(String[] args) in c:\Users\andrew\Documents\Visual Studio 2013\Projects\vts\CS\V1 Application\TestV1Part2\TestV1Part2.cs:line 29
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
為什麼?
ObjectManager 具有不同的邏輯來解析陣列以及引用和值型別的依賴關係。我們新增了一個新的引用型別陣列,在我們的程式集中沒有。
當 ObjectManager 嘗試解析依賴關係時,它會構建圖形。當它看到陣列時,它無法立即修復它,因此它會建立一個虛擬引用,然後再修復該陣列。
並且由於此型別不在程式集中,因此無法修復依賴項。由於某種原因,它不會從修復的元素列表中刪除該陣列,最後,它會丟擲異常 IncorrectNumberOfFixups
。
這是序列化過程中的一些問題。出於某種原因,它僅對新引用型別的陣列無法正常工作。
A Note:
Similar code will work correctly if you do not use arrays with new classes
還有第一種解決方法並保持相容性?
- 使用新結構而不是類的集合或使用字典(可能的類),因為字典是 keyvaluepair 的集合(它的結構)
- 如果你無法更改舊程式碼,請使用 ISerializable