8

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

 1 year ago
source link: https://www.cnblogs.com/mytudousi/p/17024915.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

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

截图.png

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

Save函数的定义如下所示。

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

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

截图.png

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

截图.png

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

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK