📜 ⬆️ ⬇️

Manage object serialization in MultiCAD.NET



In the previous article, we talked about the approach used to serialize user objects in the MultiCAD.NET API. Then we talked about the principles of applying this approach to ensure compatibility of versions of objects and considered the simplest situation when a new version of an object is obtained from the previous one by adding additional fields. Today we bring to your attention an overview of the compatibility process in case of more serious changes, such as deleting, renaming fields or changing their types.


Consider the situation when in the new version of the field object their types are renamed and changed. As an example of a user object, take the CrossMark object already familiar to us:
')
image

The class structure of this object is as follows:

 [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; } 

Suppose that in the new version of the class, it was necessary to set the corner points of the label not with points, but with vectors, while the radius field remains unchanged:

 [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; } 

Obviously, as a result of changes of this kind, the objects of the new class will not be compatible with the previous version.
In order for the new version to be able to “understand” the previous one, it is necessary to implement a mechanism for reading the required fields and “translating” the old data format into the new one. To solve this problem, MultiCAD.NET can use the standard ISerializable interface, which allows controlled serialization of objects.

To implement ISerializable , the implementation of two methods is necessary:

For our case, these methods will look like this:
 // 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(); } } 

The object now has two constructors: one of them is used when inserting an object into a drawing, the second is when reading an object from a drawing. The deserialization process is divided into two parts: reading data from an object of the current version occurs in the “normal” mode, and data from objects of the previous version is read and converted to the current format in the SerializationException section of the exception processing section, which will be thrown when trying to deserialize nonexistent fields from the previous version.
If further development of versions is planned, then an alternative would be to serialize the version of the object into a new field, and to separate the deserialization process depending on the value of this field:

 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: ... ... } 


Thus, we have considered the basic cases of the serialization of user objects in MultiCAD.NET with various options for changing their structure from version to version. Using the described approaches will allow you to create a flexible mechanism for managing the compatibility of user objects of different versions within your application.
Generally speaking, object serialization is an extensive and relevant topic, so we decided to continue to acquaint you with the implementation of this mechanism in MultiCAD.NET and soon we will bring to your attention a few more articles on this topic. In particular, we will talk about the organization of the exchange of object data between applications through serialization to external databases, as well as answer other frequently asked questions. And, as always, we are waiting for your comments and interesting topics for discussion.

Discussion of the article is also available on our forum: forum.nanocad.ru/index.php?showtopic=6516 .
Translation of the article into English: Managing serialization of custom objects in MultiCAD.NET.

Source: https://habr.com/ru/post/229175/


All Articles