2011-03-05 83 views
1

我已經提供了一個模擬該場景的最小代碼。下面是代碼:結構的二進制序列化未初始化陣列

using System; 
using System.IO; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Collections.Generic; 


namespace Serialization 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string[] annotates = { "1", "2"}; 
      Guides[] g1 = new Guides[2]; 
      g1[0].comments = (string[])annotates.Clone(); 
      g1[1].comments = (string[])annotates.Clone(); 

      Guides[] g2 = new Guides[2]; 
      g2[0].comments = (string[])annotates.Clone(); 
      g2[1].comments = (string[])annotates.Clone();//to be commented later 

      arrayStruct arrStr1 = new arrayStruct(); 
      arrStr1.guides_array = g1; 

      arrayStruct arrStr2 = new arrayStruct(); 
      arrStr2.guides_array = g2; 

      using (MoveSaver objSaver = new MoveSaver(@"C:\1.bin")) 
      { 
       MoveAndTime mv1 = new MoveAndTime(); 
       MoveAndTime mv2 = new MoveAndTime(); 
       mv1.MoveStruc = "1"; 
       mv1.timeHLd = DateTime.Now; 
       mv1.arr = arrStr1; 
       objSaver.SaveToFile(mv1); 
       mv2.MoveStruc = "2"; 
       mv2.timeHLd = DateTime.Now; 
       mv2.arr = arrStr2; 
       objSaver.SaveToFile(mv2); 
      } 

      using (MoveSaver svrObj = new MoveSaver()) 
      { 
       List<MoveAndTime> MVTobjs = svrObj.DeSerializeObject(@"C:\1.bin"); 
       foreach (MoveAndTime item in MVTobjs) 
       { 
        Console.WriteLine(item.arr.guides_array[0].comments[0]); 
       } 
      } 
     } 

    } 


    public class MoveSaver : IDisposable 
    { 
     public void Dispose() 
     { 
      if (fs != null) 
      { 
       fs.Close(); 
      } 
     } 
     FileStream fs; 
     StreamWriter sw; 
     public string filename { get; set; } 
     public MoveSaver(string FileName) 
     { 
      this.filename = FileName; 
      fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite); 
     } 

     public MoveSaver() 
     { 

     } 

     ~MoveSaver() 
     { 
      if (fs != null) 
      { 
       fs.Close(); 
      } 

     } 

     public List<MoveAndTime> DeSerializeObject(string filename) 
     { 
      List<MoveAndTime> retList = new List<MoveAndTime>(); 
      MoveAndTime objectToSerialize; 
      Stream stream = File.Open(filename, FileMode.Open); 
      BinaryFormatter bFormatter = new BinaryFormatter(); 
      while (stream.Position != stream.Length) 
      { 
       objectToSerialize = (MoveAndTime)bFormatter.Deserialize(stream); 
       retList.Add(objectToSerialize); 
      } 
      stream.Close(); 
      return retList; 
     } 


     public bool SaveToFile(MoveAndTime moveTime) 
     { 
      try 
      { 
       BinaryFormatter bformatter = new BinaryFormatter(); 
       bformatter.Serialize(fs, moveTime); 
       return true; 
      } 
      catch (Exception) 
      { 
       return false; 
      } 
     } 
    } 

    [Serializable] 
    public struct MoveAndTime 
    { 
     public string MoveStruc; 
     public DateTime timeHLd; 
     public arrayStruct arr; 
    } 

    [Serializable] 
    public struct arrayStruct 
    { 
     public Guides[] guides_array; 
    } 

    [Serializable] 
    public struct Guides 
    { 
     public string[] comments; 
     public string name; 
    } 
} 

在這種代碼的一個結構包含多個結構,其中一個包含的陣列。嘗試一下代碼,它編譯得很好,但是在真實場景中,整個數組並沒有被填充,所以會有其他數組元素未指定。要看到這種效果(在行動!)註釋行g2[1].comments = (string[])annotates.Clone();並立即嘗試代碼。您將在反序列化時遇到錯誤。我怎樣才能避免它?我應該將包含該數組的結構定義爲一個類並將它們全部新建(希望我正在尋找基於結構的類的解決方案)?

編輯: 我更改了結構類,並通過新的每個實例工作正常。這裏是代碼:

using System; 
using System.IO; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Collections.Generic; 

namespace Serialization 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string[] annotates = { "1", "2"}; 
      GuidesClass[] g1 = new GuidesClass[2]; 
      g1[0] = new GuidesClass(); 
      g1[0].comments = (string[])annotates.Clone(); 
      g1[1] = new GuidesClass(); 
      g1[1].comments = (string[])annotates.Clone(); 

      GuidesClass[] g2 = new GuidesClass[2]; 
      g2[0] = new GuidesClass(); 
      g2[0].comments = (string[])annotates.Clone(); 
      g2[1] = new GuidesClass(); 
      //g2[1].comments = (string[])annotates.Clone(); 

      array_cls arrStr1 = new array_cls(); 
      arrStr1.guides_array = g1; 

      array_cls arrStr2 = new array_cls(); 
      arrStr2.guides_array = g2; 

      using (MoveSaver objSaver = new MoveSaver(@"C:\1.bin")) 
      { 
       M_T mv1 = new M_T(); 
       M_T mv2 = new M_T(); 
       mv1.MoveStruc = "1"; 
       mv1.timeHLd = DateTime.Now; 
       mv1.arr = arrStr1; 
       objSaver.SaveToFile(mv1); 
       mv2.MoveStruc = "2"; 
       mv2.timeHLd = DateTime.Now; 
       mv2.arr = arrStr2; 
       objSaver.SaveToFile(mv2); 
      } 

      using (MoveSaver svrObj = new MoveSaver()) 
      { 
       List<M_T> MVTobjs = svrObj.DeSerializeObject(@"C:\1.bin"); 
       foreach (M_T item in MVTobjs) 
       { 
        Console.WriteLine(item.arr.guides_array[0].comments[0]); 
       } 
      } 
     } 

    } 


    public class MoveSaver : IDisposable 
    { 
     public void Dispose() 
     { 
      if (fs != null) 
      { 
       fs.Close(); 
      } 
     } 
     FileStream fs; 
     StreamWriter sw; 
     public string filename { get; set; } 
     public MoveSaver(string FileName) 
     { 
      this.filename = FileName; 
      fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite); 
     } 

     public MoveSaver() 
     { 

     } 

     ~MoveSaver() 
     { 
      if (fs != null) 
      { 
       fs.Close(); 
      } 

     } 

     public List<M_T> DeSerializeObject(string filename) 
     { 
      List<M_T> retList = new List<M_T>(); 
      M_T objectToSerialize; 
      Stream stream = File.Open(filename, FileMode.Open); 
      BinaryFormatter bFormatter = new BinaryFormatter(); 
      while (stream.Position != stream.Length) 
      { 
       objectToSerialize = (M_T)bFormatter.Deserialize(stream); 
       retList.Add(objectToSerialize); 
      } 
      stream.Close(); 
      return retList; 
     } 


     public bool SaveToFile(M_T moveTime) 
     { 
      try 
      { 
       BinaryFormatter bformatter = new BinaryFormatter(); 
       bformatter.Serialize(fs, moveTime); 
       return true; 
      } 
      catch (Exception) 
      { 
       return false; 
      } 
     } 
    } 


    [Serializable] 
    public class M_T 
    { 
     public string MoveStruc; 
     public DateTime timeHLd; 
     public array_cls arr; 
    } 

    [Serializable] 
    public class array_cls 
    { 
     public GuidesClass[] guides_array = new GuidesClass[10]; 
    } 

    [Serializable] 
    public class GuidesClass 
    { 
     public string[] comments; 
     public string name; 
    } 
} 
+1

什麼錯誤? – Oded 2011-03-05 08:58:32

+1

出於好奇,**爲什麼**是結構?他們看起來不像典型的結構(特別是因爲他們是可變的),並且沒有充分的理由,他們應該默認爲類。 – 2011-03-05 09:14:24

+0

@Oded:「輸入流不是有效的二進制格式」,在實際的代碼中,錯誤與二進制頭相關。嘗試用註釋行編譯代碼,您將看到錯誤。 – 2011-03-05 09:30:45

回答

1

我已經玩了一段代碼,我可以repro爲結構和類;最終我懷疑這裏的問題是BinaryFormatter的設計不像這樣可追加,也就是說我懷疑它是錯誤解釋當前的下一個對象的數據。

FWIW,那些真的不應該是結構,你是(IMO)可怕地over-engineering保存/加載代碼。我改變了它,以便保存方法花了List<MoveAndTime>,並且加載代碼返回了一個單個List<MoveAndTime>(即只有一個流中最外層的對象)並且它工作正常,支持我的理論。

如果你需要能夠逐漸追加單個對象,我會建議protobuf網;您可以使用SerializeWithLengthPrefix以適合追加的方式編寫對象,並使用DeserializeWithLengthPrefix從流中讀取單個對象,或者使用DeserializeItems讀取流(作爲序列)中的所有項目。


例如,使用protobuf網V2(僅可作爲代碼的時刻):

using System; 
using System.Collections.Generic; 
using System.IO; 
using ProtoBuf; 


namespace Serialization 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string[] annotates = { "1", "2" }; 
      Guides[] g1 = new Guides[2]; 
      g1[0].comments = (string[])annotates.Clone(); 
      g1[1].comments = (string[])annotates.Clone(); 

      Guides[] g2 = new Guides[2]; 
      g2[0].comments = (string[])annotates.Clone(); 
      g2[1].comments = (string[])annotates.Clone();//to be commented later 

      arrayStruct arrStr1 = new arrayStruct(); 
      arrStr1.guides_array = g1; 

      arrayStruct arrStr2 = new arrayStruct(); 
      arrStr2.guides_array = g2; 

      using (Stream file = File.Create(@"1.bin")) 
      { 
       MoveAndTime mv1 = new MoveAndTime(); 
       MoveAndTime mv2 = new MoveAndTime(); 
       mv1.MoveStruc = "1"; 
       mv1.timeHLd = DateTime.Now; 
       mv1.arr = arrStr1; 
       Serializer.SerializeWithLengthPrefix(file, mv1, PrefixStyle.Base128, Serializer.ListItemTag); 
       mv2.MoveStruc = "2"; 
       mv2.timeHLd = DateTime.Now; 
       mv2.arr = arrStr2; 
       Serializer.SerializeWithLengthPrefix(file, mv2, PrefixStyle.Base128, Serializer.ListItemTag); 
      } 

      using (Stream file = File.OpenRead(@"1.bin")) 
      { 
       List<MoveAndTime> MVTobjs = Serializer.Deserialize<List<MoveAndTime>>(file); 
       foreach (MoveAndTime item in MVTobjs) 
       { 
        Console.WriteLine(item.arr.guides_array[0].comments[0]); 
       } 
      } 
     } 

    } 

    [ProtoContract] 
    public struct MoveAndTime 
    { 
     [ProtoMember(1)] 
     public string MoveStruc; 
     [ProtoMember(2)] 
     public DateTime timeHLd; 
     [ProtoMember(3)] 
     public arrayStruct arr; 
    } 

    [ProtoContract] 
    public struct arrayStruct 
    { 
     [ProtoMember(1)] 
     public Guides[] guides_array; 
    } 

    [ProtoContract] 
    public struct Guides 
    { 
     [ProtoMember(1)] 
     public string[] comments; 
     [ProtoMember(2)] 
     public string name; 
    } 
} 

V1(作爲一個DLL,更穩定)會的工作幾乎是相同的,但沒有按不支持結構 - 只有類。

但強調:

  • 他們應該是類
  • 公共字段是一個壞主意
+0

爲工作代碼,請參閱編輯部分。 – 2011-03-08 18:21:23