ArcObjects SDK 025 对象的序列化和反序列化
在ArcObjects SDK,序列化接口是IPersistStream,该接口的定义如下。
其中GetClassID函数可以获取实际类型的唯一ID,Load函数是反序列化函数,Save函数为序列化函数。我们看下Load和Save函数是接收什么参数。
public void Save (IStream pstm,int fClearDirty); public void Load (IStream pstm);
Save函数传入IStream接口类型的对象,第二个参数是否清空该对象的脏状态。Load函数也是传入一个IStream接口类型的对象。IStream的定义如下。
从帮助中看出只有一个XMLStream继承实现了IStream接口,但实际操作的时候,保存的xml字符串会有乱码,想把这些字符串分序列化回去的时候,会报错。这个问题估计是有其他办法解决,但我一直没有找到解决办法,所以此路走不通。
实际上,除了XMLStream外,还有ESRI.ArcGIS.esriSystem.MemoryBlobStreamClass类也继承IStream接口,但不知道为什么帮助里面没有体现出来。从MemoryBlobStreamClass的命名也可以看出,使用这个类可以保存成二进制,也就是byte[],然后我们把byte[]转换成字符串就可以和其他信息一起保存成文件或者xml中的一个节点了。
public static string ToPersistString(IPersistStream pPersistStream) { if (pPersistStream == null) { return ""; } //得到ClassGuid pPersistStream.GetClassID(out Guid myClassGuid); string myClassGUID = myClassGuid.ToString(); //得到二进制信息 IMemoryBlobStream myMemoryBlobStream = new MemoryBlobStreamClass(); pPersistStream.Save(myMemoryBlobStream, 0); IMemoryBlobStreamVariant myMemoryBlobStreamVariant = myMemoryBlobStream as IMemoryBlobStreamVariant; myMemoryBlobStreamVariant.ExportToVariant(out object myObject); return myClassGUID + "," + Convert.ToBase64String(myObject as byte[]); }
需要注意的是,我们除了得到byte[]之外,还需要得到该对象所属类的ClassGUID,通过IPersistStream的GetClassID函数可以获取到,获取之后,和byte[]一起保存成字符串。只有知道这段信息保存的是哪个类的实例,才能实例化出一个对象,并把该对象转换成IPersistStream接口,最后调该接口的Load函数加载信息。
public static IPersistStream FromPersistString(string pPersistString) { if (pPersistString.Trim().Length == 0) { return null; } string[] myPersistArray = pPersistString.Split(','); if (myPersistArray.Length < 1) { throw new ArgumentException("AoSerializer error."); } Type myType = Type.GetTypeFromCLSID(new Guid(myPersistArray[0])); IPersistStream myPersistStream = Activator.CreateInstance(myType) as IPersistStream; byte[] myByteArray = Convert.FromBase64String(myPersistArray[1]); IMemoryBlobStream myMemoryBlobStream = new MemoryBlobStreamClass(); IMemoryBlobStreamVariant myMemoryBlobStreamVariant = myMemoryBlobStream as IMemoryBlobStreamVariant; myMemoryBlobStreamVariant.ImportFromVariant(myByteArray); myPersistStream.Load(myMemoryBlobStream); return myPersistStream; }
反序列化代码首先先把ClassGUID和byte[]对应的字符串分类,通过调用Type.GetTypeFromCLSID(new Guid(myPersistArray[0]));函数,可以获取具体的类型,然后通过Activator.CreateInstance(myType)函数实例化一个该类型的对象,当然该对象肯定是继承了IPersistStream接口的。
有了对象,有了数据,最后调用 myPersistStream.Load(myMemoryBlobStream);加载数据中的信息,也就是把数据中存储的信息赋给调用的对象。
一般来说,我会把保存的字符串作为大xml文件的一个属性或者节点存储,如下所示。
在第6行,定义了TextSymbol属性,该属性存储了继承ITextSymbol接口的对象,至于是哪个类,靠“,”号前面的的GUID字符串去识别,“,”号后面就是存储的具体数据。
第8行定义了MapSurroundFrame属性,该属性下存储了一个IMapSurroundFrame接口类型的对象,解析方法和TextSymbol一样。