在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一樣。