2013-03-07 82 views
0

我正在編寫一個XML序列化器,它使用反射來遞歸爬取對象的公共或專用字段以存儲爲XML並稍後重建,同時在臭名昭着的無法串行化的DataTable上測試序列化程序時,以某種方式序列化,然後嘗試重新實例化某種指針,並在此過程中跨過託管/非託管邊界,(幸好)崩潰而不是篡改內存。我需要找到解決這個問題的方法,但是由於我沒有非託管代碼的背景,我有點失落。指針/內存引用的序列化/反序列化

我知道你不能真正序列化指針或引用作爲,是因爲一個指針或引用的值是一個內存地址,你不能指望正確的對象是在經重新該地址從XML實例化指針。據我所知,我需要檢測一個會導致這個問題並忽略它的對象,或者找到並序列化被指向的對象,然後在反序列化之後,對這個對象進行deserailize,然後將指針指向該對象的位置。但我也不知道該怎麼做;我的第一個猜測是過濾Type.IsPointer似乎並沒有阻止這個問題。我可以做什麼?有更好的解決方案嗎?我可以用一些非託管代碼來做到這一點嗎?

上下文:我正在串行器可序列化類型的正常XmlSerializer的不能(IDictionary的,類型的循環引用,等等)。我的序列化器忽略屬性和ISerializeable或IXMLSerializeable的實現;它會遞歸地使用一些規則來序列化所有對象的字段。它可以工作,但它會與某些對象一起進入本機/管理邊界。我沒有使用二進制序列化,因爲我的對象不斷被修改,我不知道如何解決與二進制序列化的對象版本衝突。

編輯:這是當試圖重新實例化「System.Globalization.TextInfo」類時發生崩潰的代碼,我認爲這是深藏在DataTable某處的文化對象的一部分。這些函數以遞歸方式相互調用(始終從ReInstantiateValueInstance開始),直到初始類型參數已被重新實例化。

的管理/本地邊界的例外是在 「bestCtor.Invoke(parameters.ToArray())」,當重新實例System.Globalization.TextInfo(CultureInfo的)拋出

protected object ReCreateTypeWithParameters(Type t) 
    { 
     if (t.ToString() == "System.Type") return typeof(object); //we dont know the type of type 

     var construct = StoreUtilities.GetConstructors(t); //gets any and all constructors for an object 

     if (construct != null && construct.Count > 0) 
     { 
      var leastParams = (from c in construct 
           select c.GetParameters().Count()).Min(); 

      var bestCtor = (from c in construct 
          where c.GetParameters().Count() == leastParams 
          select c).FirstOrDefault(); //the best constructor has the least parameters - less can go wrong 

      if (bestCtor != null) 
      { 
       List<object> parameters = new List<object>(); 

       foreach (var param in bestCtor.GetParameters()) 
       { 
        parameters.Add(ReInstantiateValueInstance(param.ParameterType)); 
       } 

       return bestCtor.Invoke(parameters.ToArray()); //pointer types go boom here. 
      } 
     }   

     return null; 
    } 

    protected virtual object ReInstantiateValueInstance(Type t) 
    { 
     try 
     {  
      if (t.ToString() == "System.Type") //we don't know the Type of Type 
      { 
       return typeof(object); 
      } 
      var construct = StoreUtilities.GetConstructors(t, true); //gets an object's parameterless constructors 

      if (construct == null && t.IsGenericType) //no constructor, it's generic 
      { 
       object generic = ReCreateGenericType(t); 

       if (generic == null) //if the generic type had no constructor, we use the activator. 
       { 
        return Activator.CreateInstance(t); 
       } 
       else 
       { 
        return generic; 
       } 
      } 

      if (construct == null || construct.Count() == 0) //we have no constuctor. Try and make a placeholder object anyways. 
      { 
       return ReCreateTypeWithParameters(t); 
      } 

      object o = construct.First().Invoke(null); 
      return o; 
     } 
     catch 
     { 
      return null; 
     } 
    } 

    protected object ReCreateGenericType(Type t) 
    { 
     try 
     { 
      if (Type.IsGenericType != true) return null; 
      var construct = StoreUtilities.GetConstructors(Type, false); 

      if (construct != null && construct.Count() > 0) 
      { 
       construct = construct.OrderBy(i => i.GetParameters().Count()).ToList(); 
       var tParams = construct[0].GetParameters(); 
       List<object> paramList = new List<object>(); 

       foreach (var p in tParams) 
       { 
        if (StoreUtilities.CanStoreAsString(p.ParameterType) == true) 
        { 
         object o = Activator.CreateInstance(p.ParameterType); 
         paramList.Add(o); 
        } 
        else 
        { 
         paramList.Add(ReInstantiateValueInstance(p.ParameterType)); 
        } 
       } 

       return construct[0].Invoke(paramList.ToArray()); 
      } 
      else 
      { 
       return Activator.CreateInstance(t); 
      } 
     } 
     catch 
     { 
      return null; 
     } 
    } 
+3

一些代碼樣本。 – IAbstract 2013-03-07 01:07:29

+0

@Richard你知道你*可以*編輯你的帖子(包括標題),對吧?儘管在這種情況下,其他人已經爲你確定了標題。 – svick 2013-03-07 01:21:35

+0

我同意@IAbstract:你能解釋哪種特定類型是你有問題,還包括你用來序列化它的代碼(理想情況下刪除了不相關的東西)? – svick 2013-03-07 01:24:58

回答

0

我不知道怎麼樣託管/非託管與此有任何關聯,但實現此目的的基本方法是在序列化數據中爲內部參考提供某種抽象(標籤)。在序列化過程中,您可以添加對字典或類似字符的引用以及標籤,因此您只需序列化對象一次。

反序列化將反映這個過程中,只有創建帶有特定標籤的一次引用,其餘引用由標籤查找現有的實例。

+0

我其實已經做了那些確切的事情;這裏的問題是當我正在序列化的類型有一個值是一個文本內存地址,它以某種方式被序列化爲一個數字,如「56823136」 – Richard 2013-03-07 03:50:01

0

如說你解決不了這個問題。如果一個對象包含對「非託管數據」的引用,那麼您不可能知道。有人可能會存儲指向非託管內存在Int64Stringbyte[],等等。開發人員使用各種技巧。

如果你能以某種方式檢測到這一點,然後「忽略」具有非託管引用的對象,那麼你就失去了遊戲,因爲當你去反序列化你的數據時,最終會得到一個不完整的對象。

解決這個問題的唯一辦法就是與你序列化對象的幫助。通過它們可以實現的可選接口來幫助序列化/反序列化無法通過反射或通過屬性找到的數據。

,可以普遍工作,而這種幫助的唯一序列化往往需要你正在試圖做將有助於他們正在序列化是波蘇斯是有原因的對象...