ArcObjects SDK开发 025 AO中对象的序列化和反序列化

时间:2023-01-04 16:04:39

在ArcObjects SDK,序列化接口是IPersistStream,该接口的定义如下。

ArcObjects SDK开发 025 AO中对象的序列化和反序列化

其中GetClassID函数可以获取实际类型的唯一ID,Load函数是反序列化函数,Save函数为序列化函数。我们看下Load和Save函数是接收什么参数。

Save函数的定义如下所示。

public void Save (IStream pstm,int fClearDirty);
public void Load (IStream pstm);

Save函数传入IStream接口类型的对象,第二个参数是否清空该对象的脏状态。Load函数也是传入一个IStream接口类型的对象。IStream的定义如下。

ArcObjects SDK开发 025 AO中对象的序列化和反序列化

从帮助中看出只有一个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文件的一个属性或者节点存储,如下所示。

ArcObjects SDK开发 025 AO中对象的序列化和反序列化

在第6行,定义了TextSymbol属性,该属性存储了继承ITextSymbol接口的对象,至于是哪个类,靠“,”号前面的的GUID字符串去识别,“,”号后面就是存储的具体数据。

第8行定义了MapSurroundFrame属性,该属性下存储了一个IMapSurroundFrame接口类型的对象,解析方法和TextSymbol一样。