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;
    }
}

このコードでは、構造体に複数の構造体が含まれており、そのうちの1つに配列が含まれています。コードを試してみると、正常にコンパイルされますが、実際のシナリオでは、配列全体が埋められていないため、他の配列要素が指定されていない可能性があります。この効果を(実際に!)確認するには、行にコメントを付けて、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;
    }
}
4

1 に答える 1

1

私はコードを試してみましたが、構造体とクラスの両方を再現できます。最終的に、ここでの問題は、そのように追加できるように設計されていないこと、つまり、現在のオブジェクトの一部として次のBinaryFormatterオブジェクトからのデータを誤って解釈していることだと思います。

FWIW、それらは実際には構造体であってはなりません、そしてあなたは(IMO)保存/ロードコードをひどく過剰に設計しています。saveメソッドがを取得するように変更しましList<MoveAndTime>た。ロードコードは単一 List<MoveAndTime>を返し(つまり、ストリーム内の最も外側のオブジェクトが1つだけ)、正常に機能し、私の理論をサポートしました。

個々のオブジェクトを徐々に追加できるようにする必要がある場合は、protobuf-netをお勧めします。を使用SerializeWithLengthPrefixして、追加に適した方法でオブジェクトを記述したり、ストリームから単一のオブジェクトを読み取ったり、DeserializeWithLengthPrefixストリーム内のすべてのアイテムを(シーケンスとして)読み取ったりすることができます。DeserializeItems


たとえば、protobuf-net 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として利用可能、より安定)はほぼ同じように機能しますが、構造体をサポートしていません。クラスのみです。

しかし強調するために:

  • それらはクラスでなければなりません
  • パブリックフィールドは悪い考えです
于 2011-03-05T09:31:15.267 に答える