...

понедельник, 28 июля 2014 г.

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


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий