Как стать автором
Обновить
101.8
Нанософт разработка
Инженерная экосистема

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

Время на прочтение 4 мин
Количество просмотров 2.9K


В предыдущей статье мы рассказали о подходе, который используется для сериализации пользовательских объектов в 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 и в скором времени мы представим вашему вниманию еще несколько статей по этой тематике. В том числе, мы расскажем об организации обмена данными объектов между приложениями через сериализацию во внешние базы данных, а также ответим на другие, часто возникающие вопросы. И, как всегда, ждем ваших комментариев и интересных тем для обсуждения.

Обсуждение статьи доступно также и на нашем форуме: forum.nanocad.ru/index.php?showtopic=6516.
Перевод статьи на английский: Managing serialization of custom objects in MultiCAD.NET.
Теги:
Хабы:
+9
Комментарии 0
Комментарии Комментировать

Публикации

Информация

Сайт
www.nanocad.ru
Дата регистрации
Дата основания
Численность
Неизвестно
Местоположение
Россия