2011-03-21 39 views
15

Tôi đang cố gắng deserialize "SomeClass" với một phiên bản cũ của một ứng dụng. Tôi nhận được điều này bên dưới ngoại lệDeserialization tương thích ngược

System.Runtime.Serialization.SerializationException: ObjectManager tìm thấy số lượng bản sửa lỗi không hợp lệ. Điều này thường chỉ ra một vấn đề trong Formatter.

Deserialization ném ngoại lệ khi tôi serialize phiên bản 0.9 và cố gắng deserialize sử dụng phiên bản 0.8. Tôi nghĩ rằng các thuộc tính OptionalField sẽ làm các trick, nhưng nó đã không.

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

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

Vì tôi không thể thay đổi phiên bản 0.8, làm cách nào để thêm nhiều trạng thái hơn vào đối tượng Foo sao cho các phiên bản trước có thể deserialize bất cứ điều gì họ có thể?

Bất kỳ con trỏ nào cũng sẽ thực sự được đánh giá cao.

Cập nhật 1 Bar và Zoo là các lớp khác được tuần tự hóa và chứa Hashtables và các công cụ có thể tuần tự khác. Mọi thứ đều có thể tuần tự hóa trong các lớp đó. Ngoài ra, tôi không có bất kỳ thanh chống.

+0

Trường có tùy chọn hay không không liên quan ở đây - thực tế là việc tuần tự hóa không hoạt động trên các phiên bản, AFAIK; đó không phải để nói bạn _can't_ thêm thành viên, tất nhiên bạn có thể, nhưng, ví dụ, tôi không thể chỉ định một loại nguyên văn và deserialize mục serialized với hiện tại - một cái gì đó để làm với các hội đồng, hoặc các loại 'token ', Tôi nghĩ vậy. –

+0

kareph, loại thực sự của 'Zoo' là gì? Tôi nhớ một số loại (mảng) chỉ không hoạt động đúng. –

+0

Bạn có sẵn sàng sử dụng xml serialization hơn là serialization nhị phân không? Điều đó sẽ an toàn hơn cho phiên bản. – code4life

Trả lời

26

Thứ nhất, không bao giờ không bao giờ sử dụng chức năng serialization của CLR cho bất cứ điều gì tương tự như dài hạn lưu trữ. Chúng tôi làm cho sai lầm đó thường một lần, đặt các đối tượng trong một lĩnh vực cơ sở dữ liệu blob và vỗ nhẹ vào chính mình trong suy nghĩ lại chúng ta thông minh. Và sau đó CLR nhận được một bản vá hoặc hội đồng của chúng tôi thay đổi phiên bản và bạn đang hơi say. Vì vậy, không làm điều đó.

Nếu bạn vẫn muốn làm điều đó, cách tốt nhất để quản lý vấn đề là để tạo của riêng bạn SerializationBinder mà trông giống như sau:

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; 
    } 
} 

Đặt Binder tài sản của formatter bạn đang sử dụng trước để deserializing để nó ghi đè các giá trị mặc định.

Lưu ý rằng tôi không cung cấp giải pháp thả tại đây, tôi khuyên bạn nên giải quyết vấn đề. Một khi bạn đã chuyển đổi ra khỏi bất cứ điều gì bạn đang làm, điều tra các công nghệ serialization khác như protobuf, hoặc viết của riêng bạn. Dù bằng cách nào bạn cũng không bao giờ nên dựa vào CLR để hỗ trợ tuần tự hóa dài hạn.

+2

nhận xét 'KHÔNG BAO GIỜ' của bạn cũng áp dụng cho tuần tự hóa XML? Dường như với tôi rằng với DataContract và DataMember có kiểm soát tốt cấu trúc được tạo ra. Sẽ được quan tâm để có được ý kiến ​​của bạn về điều đó. – paul

+0

Không, nhưng trình tuần tự nhị phân không phù hợp cho việc tuần tự hóa dài hạn. Nó phù hợp nhất để bơm byte qua dây, ví dụ, một ứng dụng client-server. WebForms ví dụ sử dụng nó. – Sebazzz

2

Có vẻ như một cách để làm điều này là có một đối tượng được phiên bản, theo cách đó bạn có thể thử deserializing đối tượng bằng cách sử dụng phiên bản mới nhất. Nếu điều đó không hiệu quả, hãy lùi lại phiên bản cho đến khi phiên bản thành công. Sau đó, khi bạn có đối tượng của mình, hãy cập nhật nó lên phiên bản mới nhất của đối tượng và sử dụng các giá trị mặc định cho bất kỳ trường nào bạn không có dữ liệu.

+0

Nếu chúng tôi hạ cấp (kết quả của rollback) ứng dụng của chúng tôi thì chúng tôi sẽ có các trường bị thiếu (thay vì thiếu dữ liệu); anyways những gì bạn đang nói là những gì nó nên được. – karephul

+0

Tôi biết đó là những gì các lập trình viên C sử dụng để làm. Tôi nghĩ rằng chúng tôi đang lập trình ở mức trừu tượng rất cao và điều này có thể là vấn đề tiêu chuẩn. Cảm ơn thông tin chi tiết của bạn. – karephul

0

Thuộc tính optional field cần phải thực hiện thủ thuật. Bạn có thể đăng các lớp thực tế mà bạn đang cố gắng sắp xếp theo thứ tự không.

Bạn có thể thử những điều đầu tiên -

chuyển đổi structs nếu có để classes

thử Soap Serialization thay vì binary serilization

+0

Tôi đã cập nhật bài đăng. – karephul

+0

bạn có thử xà phòng tuần tự không? –

4

Nếu các nhà thầu cho mỗi phiên bản tương thích (ví dụ:có một hàm tạo tham số hoặc Foo(Bar b) cho cả hai phiên bản), bạn có thể gọi

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

Trước khi deserializing luồng của bạn.

3

Là tư vấn cho những người đang điều tra vấn đề này "trước khi quá muộn" ... Tôi khuyên bạn không nên kiên trì thông qua BinaryFormatter. Bạn có thể chuyển nhanh giữa 2 ứng dụng miền đồng bộ, nhưng đó là về IMO. Các công cụ tuần tự hóa khác tồn tại mà không có những vấn đề này. Về mặt nhị phân, protobuf-net là một lựa chọn khá hợp lý - cho phép thêm/xóa/đổi tên vv mà không bị đau.

Các vấn đề liên quan