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