6

я должен работать в старом приложении, которое используется BinaryFormatter для сериализации данных приложения в FileStream (скажем, в файл с именем «data.oldformat») без optimizazion основного класса был отмечен атрибутомISerializable и обратная совместимость

<serializable()>public MainClass 
....... 
end class 

и код сериализации

dim b as new binaryformatter 
b.serialize(mystream,mymainclass) 

в попытке оптимизировать процесс/десериализации сериализации Я просто сделал класс реализует интерфейс ISerializable и написал некоторые оптимизированный seriali зация Подпрограмма

<serializable()>public MainClass 
     implements ISerializable 
....... 
end class 

Оптимизация работает очень хорошо, но я должен найти способ reatrive данных внутри старых файлов для обеспечения обратной совместимости.

Как это сделать?

Пьерлуиджи

ответ

4

stmax имеет отличный ответ, но я бы осуществить это, как это, который использует SerializationEntry.GetEnumerator() вместо try/catch. Этот способ чище и значительно быстрее.

public MainClass(SerializationInfo info, StreamingContext context) { 
    int version = 0; 
    foreach (SerializationEntry s in info) 
    { 
     if (s.Name == "version") 
     { 
      version = (int)s.Value; 
      break; 
     } 
    } 

    switch (version) { 
     case 0: 
     // deserialize "old format" 
     break; 
     case 1: 
     // deserialize "new format, version 1" 
     break; 
     default: 
     throw new NotSupportedException("version " + version + " is not supported."); 
    } 
} 

Я предпочел бы версию LINQ, используя .FirstOrDefault(), но SerializationInfo не реализует IEnumerable - в лицо, достаточно странно, он даже и не реализовать старый IEnumerable интерфейс.

0

Просто попробуйте то же самое вы делали до сих пор

BinaryFormatter b = new BinaryFormatter(); 
MainClass a = b.DeSerialize(mystream) as MainClass; 

Реализация ISerializable не изменил свой оригинальный класс, в основном вы только что добавили некоторые методы

+0

Я добавил необходимый конструктор (serializationInfo info, streamingContext context), поэтому я не могу использовать b.deserialize, не зная, как основной класс сохранил свои собственные данные во время сериализации по умолчанию – pierusch

0

При сериализации объектов добавьте дополнительное поле Version (это не должно содержать слишком много служебных данных). Затем в вашем методе GetObjectData сначала попытайтесь получить поле версии и на основе того, существует ли это или нет (путем исключения SeializationException) десериализовать старый путь или новый способ. Старый способ будет просто сериализовать все данные, чтобы вы могли просто вызвать Get ... для всех полей.

+0

, это нормально для процедуры сериализации, которая использует getObjectData, но проблема заключается в процедуре десериализации, которая использует специализированный конструктор новый (информация как serializationinfo, контекст как serializationcontext) старая версия mainClass не реализовала ISerializable, поэтому я не знаю, как извлекать данные с помощью streaminginfo object – pierusch

0

Ваш предыдущий код должен работать. Вы получаете исключение? Попробуйте использовать новый конструктор:

Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext) 
+0

I Had..but Требуется знать, как двоичный формат сохраняет данные, когда класс помечен как сериализуемый ... – pierusch

4

, так как вы уже реализовали интерфейс ISerializable, вы, вероятно, также уже добавили нужный конструктор:

public MainClass(SerializationInfo info, StreamingContext context) {} 

вы можете использовать инфо-объект передается к конструктору для извлечения данных из сериализованного файла. (т. Е. Когда не выполняется ISerializable), имена полей используются в качестве идентификаторов во время сериализации. поэтому, если ваш старый класс имел поле «ИНТ х» вы можете десериализации это с помощью:

this.x = info.GetInt32("x"); 

для новых версий я обычно добавить запись «версии» во время сериализации, как это:

public void GetObjectData(SerializationInfo info, StreamingContext context) { 
    info.AddValue("version", 1); 
    info.AddValue("othervalues", ...); 
} 

во время десериализации вы можете проверить эту запись версии и десериализации соответственно:

public MainClass(SerializationInfo info, StreamingContext context) { 
    int version; 
    try { 
     version = info.GetInt32("version"); 
    } 
    catch { 
     version = 0; 
    } 

    switch (version) { 
     case 0: 
     // deserialize "old format" 
     break; 
     case 1: 
     // deserialize "new format, version 1" 
     break; 
     default: 
     throw new NotSupportedException("version " + version + " is not supported."); 
    } 
} 

я не компилируется этот код, может содержать опечатки.

надеюсь, что это поможет.

+0

отличный ответ stmax! как u нашел поведение по умолчанию для объекта бинарного преобразования? – pierusch

+3

Я сделал следующее, чтобы найти «имена» записей, которые были сериализованы с поведением по умолчанию: foreach (запись SerializationEntry в файле info.GetEnumerator()) {Trace.WriteLine (entry.Name); } – stmax

+0

Вместо try/catch при получении «версии» вместо этого используйте SerializationInfo.GetEnumerator() и найдите поле «версия». Это чище, и если поле не найдено, то исключение исключения исключений делает всю десериализацию (в моем тестировании) в 2 раза быстрее. SerializationInfo.Get() внутренне использует тот же линейный поиск, что и сам с перечислителем, делая их как O (n) в количестве полей. –