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