2011-03-21 96 views
15

我試圖用舊版本的應用程序反序列化「SomeClass」。我得到以下異常反序列化向後兼容性

System.Runtime.Serialization.SerializationException:ObjectManager發現無效數量的修正。這通常表示Formatter中存在問題。

反序列化拋出異常的時候我序列化版本0.9,並使用0.8版本嘗試反序列化。我認爲OptionalField屬性可以做到這一點,但事實並非如此。

// Version 0.8 
[Serializable()] 
class Foo{ 
    Bar b; 
} 

// Version 0.9 
[Serializable()] 
class Foo{ 
    Bar b; 
    [OptionalField] 
    Zoo z; 
} 

既然我不能改變版本0.8,我應該怎麼添加更多的狀態Foo對象,使得以前的版本可以反序列化一切可能?

任何指針將非常感激。

更新1 酒吧和動物園的其他類,其是可序列化,幷包含哈希表和其他序列化的東西。一切都可以在這些類中進行序列化。 另外,我沒有任何支柱。

+0

字段是否可選與此無關 - 事實是序列化不能跨越各個版本AFAIK;這並不是說你不能添加成員,當然你可以,但是,例如,我不能僅僅定義一個逐字類型,並且反序列化與現有序列化的項目 - 與程序集或類型的令牌',我想。 – 2011-03-21 18:34:48

+0

kareph,「動物園」的真實類型是什麼?我記得有些類型(數組)沒有正確工作。 – 2011-03-21 18:57:34

+0

你願意使用xml序列化而不是二進制序列化嗎?這會更安全。 – code4life 2011-03-21 19:09:13

回答

26

首先,從來就不曾使用CLR的序列化功能對於任何類似於長期存儲。我們通常犯這個錯誤一次,將對象放在一個blob數據庫字段中,並在後面輕拍自己,認爲我們很聰明。然後CLR得到一個補丁或我們的程序集更改版本,然後你就搞定了。所以不要這樣做。

如果您仍然想這樣做,來管理這個問題的最好辦法是創建自己的SerializationBinder看起來是這樣的:

public sealed class CustomBinder : SerializationBinder { 

    public override Type BindToType(string assemblyName, string typeName) { 

     Type typeToDeserialize = null; 

     if (typeName.IndexOf("SomeType") != -1) { 
      typeToDeserialize = typeof(Foo.Bar.Bax.NewType); 
     } 
     else if (typeName.IndexOf("SomeOtherType") != -1) { 
      typeToDeserialize = typeof(Foo.Bar.Bax.SomeOtherNewType); 
     } 
     else { 
      // ... etc 
     } 

     return typeToDeserialize; 
    } 
} 

設置你之前使用格式化的Binder財產以反序列化,以便覆蓋默認值。

請注意,我並沒有在這裏提供解決方案,我建議如何解決問題。一旦你完成了任何你正在做的事情,請調查其他序列化技術,比如protobuf,或者自己寫。無論哪種方式,您都不應該依賴CLR來獲得長期序列化支持。

+2

你的'從不'評論也適用於XML序列化?在我看來,使用DataContract和DataMember可以很好地控制生成的結構。有興趣就此發表你的看法。 – paul 2013-04-02 12:35:11

+0

否,但二進制串行器不適合長期序列化。它最適合通過線路抽取字節,例如客戶端 - 服務器應用程序。例如WebForms使用它。 – Sebazzz 2015-05-28 11:07:21

2

似乎有一種方法可以使用版本化對象,這種方式可以嘗試使用最新版本反序列化對象。如果這樣做不起作用,請退回版本直到成功。然後,一旦擁有了對象,就將其更新爲最新版本的對象,併爲任何沒有數據的字段使用默認值。

+0

如果我們降級(回滾的結果)我們的應用程序,那麼我們將有缺少的字段(而不是數據缺失);無論如何你說的是它應該是。 – karephul 2011-03-21 20:07:07

+0

我知道這就是C程序員用來做的事情。我認爲我們正在編程的抽象程度非常高,這可能是標準問題。感謝您的見解。 – karephul 2011-03-21 20:10:47

0

optional field屬性本應該做的。你能發佈你試圖序列化的實際類嗎?

你可以先試試這些東西 -

如果任何轉換structsclasses

嘗試Soap Serialization代替binary serilization

+0

我已更新該帖子。 – karephul 2011-03-21 20:11:31

+0

是否嘗試過使用soap序列化? – 2011-03-22 18:29:47

4

如果每個版本的構造函數是兼容的(例如,有一個無參數或Foo(Bar b)構造兩個版本),你可以調用

BinaryFormatter formatter = new BinaryFormatter(); 
formatter.AssemblyFormat = Formatters.FormatterAssemblyStyle.Simple; 

反序列化的流之前。

3

作爲調查此問題的人們的「諮詢意見」之前「太遲了......」我強烈建議不要通過BinaryFormatter堅持。在同步的2個應用程序域之間進行瞬時傳輸是可以的,但這與IMO有關。其他序列化工具不存在這些問題。在二進制方面,protobuf-net是一個非常合理的選項 - 允許無痛地添加/刪除/重命名等。