none
シリアル化ができません RRS feed

  • 質問

  • はじめまして。

    最近C#の勉強を始めました。超初心者です。

    下記のフィールドを持つクラスをListで管理しています。

    public class Plan{

    //---------日時構造体---------
            public struct Date
            {
                public int year;           //西暦
                public int month;          //月
                public int day;            //日
                public int hour;           //時
                public int minute;         //分
            }

            private string _name;            //予定名
            private string _content;         //内容
            private Date _start;              //予定開始日
            private Date _end;               //予定終了日

    }

    この<List>Planをシリアル化してXML形式で出力したいのですが、

    下記コードではシリアル化の段階で 

    「型 'System.ComponentModel.List`1[Schedule.Plan]' を反映中にエラーが発生しました。」というエラーが生じます。

         //XmlSerializerにオブジェクトの型を指定
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<Plan>));   ←  この時点でエラー発生

            //ファイルストリームを上書きモードで開く
            using (FileStream fm = File.Open(@"C:Users\\Program Files", FileMode.Create/*, FileAccess.Read, FileShare.None*/)) 
            {
                //シリアル化して保存
                xmlSerializer.Serialize(fm, listPlan);
            }

    何が間違っているのでしょうか?

    またその対処法がありましたら教えていただけませんでしょうか。

    以上、宜しくお願い致します。

    2012年6月18日 2:20

回答

  • 一応、Visual Studio 2010 SP1 / .NET4 ClientProfile でも試してみましたが、問題なく実行できました。
    (一応、.NET 2.0 しか入っていない古い XP でも問題なくシリアライズできます)

    ちなみに、(エラーメッセージではなく)具体的に発生している例外やスタックトレースといったものも提示してみてはどうでしょう?

        class Schedule
        {
            static void Main(string[] args)
            {
                var s = new List<Plan>() { new Plan(), new Plan() };
    
                using (MemoryStream ms = new MemoryStream())
                {
                    new XmlSerializer(typeof(List<Plan>)).Serialize(ms, s);
    
                    ms.Position = 0;
                    StreamReader r = new StreamReader(ms);
                    Console.WriteLine(r.ReadToEnd());
                }
    
                Console.ReadLine();
            }
    
            public class Plan
            {
                //---------日時構造体---------
                public struct Date
                {
                    public int year;           //西暦
                    public int month;          //月
                    public int day;            //日
                    public int hour;           //時
                    public int minute;         //分
                }
    
                private string _name;            //予定名
                private string _content;         //内容
                private Date _start;              //予定開始日
                private Date _end;               //予定終了日
            }
        }
    

    2012年6月19日 9:26
  • もっと別のところに原因があるのではないでしょうか? 記載されている内容だけなら、何も問題なく実行できてしまいます。

    ちなみに、Plan のメンバがすべて private なので、出力される内容は <ArrayOfPlan><Plan /><Plan />....<Plan /></ArrayOfPlan> になりますが、大丈夫ですか?

    2012年6月18日 3:55
  • 本筋ではないですが K. Takaoka 様の例示コードを動かそうとしたのですが、Shcedule クラスが Public でないため Plan クラスにアクセスできないと実行時に怒られました。

    指定なしだとデフォルトのアクセシビリティが internal だから怒られたのだと思いますが、デフォルト設定を何かの指定で変更可能なのでしょうか?

    属性での XML の整形に気を惹かれてためしただけで、本筋と関係なくてすいません。

    2012年6月19日 16:51

すべての返信

  • もっと別のところに原因があるのではないでしょうか? 記載されている内容だけなら、何も問題なく実行できてしまいます。

    ちなみに、Plan のメンバがすべて private なので、出力される内容は <ArrayOfPlan><Plan /><Plan />....<Plan /></ArrayOfPlan> になりますが、大丈夫ですか?

    2012年6月18日 3:55
  • ご返信ありがとうございます!

    メンバがprivateだと<ArrayOfPlan><Plan /><Plan />....<Plan /></ArrayOfPlan>なってしまうのですね。

    知らなかったです。すべてpublicに修正します。

    またエラー原因は別のところにある可能性があるとのことですね。

    ありがとうございます。

    もう少し原因を探してみようと思います。

    後程またご質問させていただくかもしれませんが、

    その際はどうぞ宜しくお願い致します。

    2012年6月18日 4:10
  •  いや、多分、エラーで正解です、バージョンによって。→ジェネリックのシリアル化 (wankuma.com) この経験があるので、未だにシリアル化するためだけに、クラス作ってます(^-^;
    これからはバージョンも知らせてくださいね。


    Jitta@わんくま同盟

    2012年6月18日 20:59
  • <del>

    XmlSerializerクラス

    ArrayList およびジェネリック リストのシリアル化

    次のようなデータについては、XmlSerializer でシリアル化または逆シリアル化することはできません。

    • ArrayList の配列。
    • List<T> の配列。
    と書かれていますが、ちゃんと読みましたか?</del>

    delタグは編集中のみのサポートだったかな

    • 編集済み 佐祐理 2012年6月19日 0:26 間違ってました
    2012年6月18日 22:35
  • XmlSerializerクラス

    ArrayList およびジェネリック リストのシリアル化

    次のようなデータについては、XmlSerializer でシリアル化または逆シリアル化することはできません。

    • ArrayList の配列。
    • List<T> の配列。
    と書かれていますが、ちゃんと読みましたか?
    tatibanaiさんのコードを見る限り、シリアライズ対象はList<T>であってList<T>[]ではないようですが。
    2012年6月18日 23:45
  • 一応、前回の投稿時に実際に動かして正常に動くことは確認していますよ。
    # 確認したかったのは、属性未指定で Root 要素の Items が何に展開されるかだったんですけどね

    tatibanai さん
    一般的に、XMLシリアライズは、特定の XML を作成するために使用されることが多く、スキーマや属性を使用して .NET の型情報と XML の間の関連付けを行うように利用することが多いです。

    属性を使用することで、

    <Plan Name="name">
    <Year>YYYY</Year><Month>MM</Month><Day>DD</Day>
    </Plan>
    とか
    <Plan Name="name" Y="yyyy" M="mm" D="dd">
    plan description
    </Plan>

    みたいに、どのようなXMLを書きだしたいかを指定することになります。(そして、それはどのようなXMLを読み込めるかの指定にもなります)
    2012年6月18日 23:50
  • あれ…タイトルの方は「ArrayList およびジェネリック リストのシリアル化(Serialization of ArrayList and Generic List)」なのでArrayListとList<T>が問題なのだと思ってました。失礼しました。

    2012年6月19日 0:25
  • 皆さんご回答ありがとうございます。

    すみません記載するべき情報が少なかったですね。

    バージョンは4.0・・・だと思います。

    他にも足りない情報がありましたらご指摘頂けますでしょうか。

    List<T>は配列ではなく、List<T>単体で書き出したいです。

    それでもシリアル化できないのでしょうか・・・?

    K.Takaokaさん、

    XMLシリアライズは、特定のXMLを作成するために使用するとのことですね。

    私は用途を間違えていたかもしれません。

    私の目的はある特定のXMLを書き出したいのではなく、ただ単にデータの保存・読み込みでした。

    データの保存・読み込みの手段としてXML形式でデータを扱おうと考えただけでした・・・。

    この目的の場合ですと、無理にXMLで書き出す必要は無い・・・ですよね。

    もし無理そうでしたら、方針を変えてバイナリで書き出してみようと思っています。

    2012年6月19日 1:22
  • と書かれていますが、ちゃんと読みましたか?

     読んでませんでした...Ver 2.0 の頃は、tatibanaiさんが書かれている実行時例外が出ていました。Silverlight 2 ベータを遊んでいるときに List<> がシリアライズされる事に気がつき、Ver 3.5(3.0 かも?)でも実行時例外にならないことを確認しました。Ver 4 では確認していません。必ず後述のようなクラスを作るようにしているからです。ドキュメントが更新されていない?でも、tatibanaiさんは、4 でもできないのですよね。。。


    私の目的はある特定のXMLを書き出したいのではなく、ただ単にデータの保存・読み込みでした。

     私はその目的で XML シリアル化しています。これだとテキスト ファイルに落ち、エディターで修正できますから。

     なお、List<T> をシリアル化できない場合、継承したクラスを作ってみて下さい。Ver 2.0 の頃から、これでシリアル化しています。まぁ、親クラスがシリアル化できないはずなのに、何故これがシリアル化できるのか、不思議なんだけど。

    [Serializable]
    public class HogeList : List<Hoge>
    {
        // 中は空で良い
    }
    

    Jitta@わんくま同盟

    2012年6月19日 6:42
  •  読んでませんでした...Ver 2.0 の頃は、tatibanaiさんが書かれている実行時例外が出ていました。
    それは、XmlSerializerではなくSoapFormatterの話では?
    2012年6月19日 7:01
  • > 私の目的はある特定のXMLを書き出したいのではなく、ただ単にデータの保存・読み込みでした。
    > データの保存・読み込みの手段としてXML形式でデータを扱おうと考えただけでした・・・。

    XML にしたい理由があれば、十分だと思います。たとえば、人間が読めるとか、テキストとして書き換えることができるとかですね。

    例として挙げられているようなスケジュール?を保存する場合、少し書き換えて読み込むような用途を考えると XML になっているほうが便利でしょう。その場合でも、標準の XmlSerializer のシリアライズ結果に不満があれば属性を使用して XML の整形を行うことができる、程度でいいかと思います。(抽象クラスを使いだしたりすると、属性が必須になってきたりしますが)

    2012年6月19日 9:18
  • 一応、Visual Studio 2010 SP1 / .NET4 ClientProfile でも試してみましたが、問題なく実行できました。
    (一応、.NET 2.0 しか入っていない古い XP でも問題なくシリアライズできます)

    ちなみに、(エラーメッセージではなく)具体的に発生している例外やスタックトレースといったものも提示してみてはどうでしょう?

        class Schedule
        {
            static void Main(string[] args)
            {
                var s = new List<Plan>() { new Plan(), new Plan() };
    
                using (MemoryStream ms = new MemoryStream())
                {
                    new XmlSerializer(typeof(List<Plan>)).Serialize(ms, s);
    
                    ms.Position = 0;
                    StreamReader r = new StreamReader(ms);
                    Console.WriteLine(r.ReadToEnd());
                }
    
                Console.ReadLine();
            }
    
            public class Plan
            {
                //---------日時構造体---------
                public struct Date
                {
                    public int year;           //西暦
                    public int month;          //月
                    public int day;            //日
                    public int hour;           //時
                    public int minute;         //分
                }
    
                private string _name;            //予定名
                private string _content;         //内容
                private Date _start;              //予定開始日
                private Date _end;               //予定終了日
            }
        }
    

    2012年6月19日 9:26
  • > 'System.ComponentModel.List`1[Schedule.Plan]'

    Schedule.Plan となっているのでネストされた型かと思いましたが、フルネームで出ているだけなのでnamespaceですね。

    気になるのは、System.ComponentModel.List`1 なんてクラスは標準では存在しないと思うので、このあたりがあやしいように思います。(通常は System.Collections.Generic.List`1)

    2012年6月19日 9:54
  • 本筋ではないですが K. Takaoka 様の例示コードを動かそうとしたのですが、Shcedule クラスが Public でないため Plan クラスにアクセスできないと実行時に怒られました。

    指定なしだとデフォルトのアクセシビリティが internal だから怒られたのだと思いますが、デフォルト設定を何かの指定で変更可能なのでしょうか?

    属性での XML の整形に気を惹かれてためしただけで、本筋と関係なくてすいません。

    2012年6月19日 16:51
  • K.Takaokaさん

    ありがとうございます!!

    できました!ついにできましたよ!!感動です!!!

    K.Takaokaさんの記述してくれた、

    ソースコードを使わせていただきました。

    するとあれだけ手こずったシリアル化が一瞬で成功しました!

    結局何が悪かったのか正直よくわかりませんが、

    おそらくシリアル化するソースコードが間違っていたのだと思います。

    本当にありがとうございました!!

    また、ご回答して下さりました

    JJittaさん、佐祐理さん、Hongliangさん、Kyano30さん

    ありがとうございました!

    2012年6月20日 6:01
  • tatibanai さん、問題が無事解決されたようでしたので役に立ったと思われる投稿に対して、私の方から回答としてマークをさせていただきました。
    回答としてマークは tatibanai さんの方で自由に設定・解除ができますので、必要に応じて追加でマークしたり、すべてのマークを外して未解決状態に戻すことができますのでご利用ください。

    なお、私も手元で試させていただきましたが、XmlSerializer での対象クラスは public のアクセシビリティが必要なので、入れ子のクラスの場合は、外側のクラス(K. Takaoka さんのサンプルで言えば Schedule クラス)も public であることが必要なようです。ご参考までに。

    2012年6月22日 22:55
    モデレータ