Управление сериализацией объектов в MultiCAD.NET

от автора

В предыдущей статье мы рассказали о подходе, который используется для сериализации пользовательских объектов в MultiCAD.NET API. Тогда мы говорили о принципах применения данного подхода для обеспечения совместимости версий объектов и рассмотрели самую простую ситуацию, когда новая версия объекта получается из предыдущей путем добавления дополнительных полей. Сегодня мы предлагаем вашему вниманию обзор процесса обеспечения совместимости в случае более серьёзных изменений, таких как удаление, переименование полей или изменение их типов.

Рассмотрим ситуацию, когда в новой версии объекта поля переименованы и изменены их типы. В качестве примера пользовательского объекта возьмем, уже знакомый нам, объект CrossMark:

image

Структура класса данного объекта выглядит следующим образом:

[CustomEntityAttribute("1C925FA1-842B-49CD-924F-4ABF9717DB62", 2, "Crossmark", "Crossmark Sample Entity")] [Serializable] public class CrossMark : McCustomBase {   private Point3d pnt1;   private Point3d pnt2;   private Point3d pnt3;   private Point3d pnt4;   private double radius; } 

Допустим, что в новой версии класса, потребовалось задавать угловые точки метки не точками, а векторами, поле radius при этом остается без изменений:

[CustomEntityAttribute("1C925FA1-842B-49CD-924F-4ABF9717DB62", 3, "Crossmark", "Crossmark Sample Entity")] [Serializable] public class CrossMark : McCustomBase {   private Vector3d v1;   private Vector3d v2;   private Vector3d v3;   private Vector3d v4;   private double radius; } 

Очевидно, что в результате изменений такого рода объекты нового класса не будут обладать совместимостью с предыдущей версией.
Для того, чтобы новая версия смогла «понимать» предыдущую, необходимо реализовать механизм чтения необходимых полей и «перевод» старого формата данных в новый. Для решения этой задачи в MultiCAD.NET может быть использован стандартный интерфейс ISerializable, который позволяет осуществлять контролируемую сериализацию объектов.

Для реализации ISerializable необходима имплементация двух методов:

  • public void GetObjectData(SerializationInfo info, StreamingContext context) — используется для сериализации объекта.
  • public CrossMark(SerializationInfo info, StreamingContext ctx) — конструктор, использующийся для десериализации.

Для нашего случая эти методы будут выглядеть следующим образом:

// Serialization public void GetObjectData(SerializationInfo info, StreamingContext context) {   info.AddValue("vec1", v1);   info.AddValue("vec2", v2);   info.AddValue("vec3", v3);   info.AddValue("vec4", v4);   info.AddValue("radius", radius); } 

// Deserialization public CrossMark(SerializationInfo info, StreamingContext ctx) {   radius = info.GetDouble("radius");   try   {     v1 = (Vector3d)info.GetValue("vec1", typeof(Vector3d));     v2 = (Vector3d)info.GetValue("vec2", typeof(Vector3d));     v3 = (Vector3d)info.GetValue("vec3", typeof(Vector3d));     v4 = (Vector3d)info.GetValue("vec4", typeof(Vector3d));   }   catch (System.Runtime.Serialization.SerializationException)   {     Point3d pnt1 = (Point3d)info.GetValue("pnt1", typeof(Point3d));     Point3d pnt2 = (Point3d)info.GetValue("pnt2", typeof(Point3d));     Point3d pnt3 = (Point3d)info.GetValue("pnt3", typeof(Point3d));     Point3d pnt4 = (Point3d)info.GetValue("pnt4", typeof(Point3d));          v1 = pnt1.GetAsVector();     v2 = pnt2.GetAsVector();     v3 = pnt3.GetAsVector();     v4 = pnt4.GetAsVector();   } } 

Объект теперь имеет два конструктора: один из них используется при вставке объекта в чертеж, второй — при чтении объекта из чертежа. Процесс десериализации разделен на две части: чтение данных из объекта текущей версии происходит в «штатном» режиме, а данные объектов предыдущей версии зачитываются и приводятся к текущему формату в секции обработки исключения SerializationException, которое будет выброшено при попытке десериализации несуществующих полей из предыдущей версии.
Если планируется дальнейшее развитие версий, то альтернативным вариантом может быть сериализация версии объекта в новое поле, и разделение процесса десериализации в зависимости от значения этого поля:

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

public CrossMark(SerializationInfo info, StreamingContext ctx) {   int version = info.GetInt("version");   switch (version)   {     case 1:         ...     case 2:         ...     ...     } 

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

ссылка на оригинал статьи http://habrahabr.ru/company/nanosoft/blog/229175/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *