2011-03-05 68 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