Looking for c# Keywords? Try Ask4Keywords

C# Language Некоторые исправления в обратной совместимости


пример

Этот небольшой пример показывает, как вы можете потерять обратную совместимость в своих программах, если заранее не позаботитесь об этом. И способы получения большего контроля над процессом сериализации

Сначала мы напишем пример первой версии программы:

Версия 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».

Это некоторые «gotchas» в процессе сериализации. По какой-то причине он работает некорректно только для массивов новых ссылочных типов.

A Note:
Similar code will work correctly if you do not use arrays with new classes

И первый способ исправить это и поддерживать совместимость?

  • Используйте коллекцию новых структур, а не классы или используйте словарь (возможные классы), потому что словарь представляет собой набор ключейvaluepair (его структура)
  • Используйте ISerializable, если вы не можете изменить старый код