(C#)オブジェクトをファイルに保存して復元する・その2

SQLの条件式のオブジェクトをファイルに保存して、そこから復元する試みの続き。前回はJSONでやってみたが問題があったので、今回はXMLでやってみる。
エンコードの問題を追記した。2017/10/16



まず保存したいSQLの条件式は、たとえば下記のような感じ。まあ普通の式です。

[英語] >= 80 and [テスト名称] = '2017年7月末'

これを文字列ではなく、式オブジェクトのツリーで管理したい。ファイルに保存して、保存したファイルから読み込んでオブジェクトを復元したいというのが、やりたいこと。

前回と同じ手順でやってみる。

手順

(1)参照設定に「System.Runtime.Serialization.dll」を追加する。

(2)usingを書く。
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
(3)クラスを書く。
ここは前回と同じです。

(4)オブジェクトをXMLテキストに変換する。
今回はファイルに保存せずにテキストに変換することにする(その方が確認しやすいし)。変換はDataContractSerializerクラスを使います。

// 論理式を保存する
        internal static string getXml(mm論理式 ex)
        {
            var dcs = new DataContractSerializer(ex.GetType());

            // 文字列に書き込むよ
            StringWriter wt = new StringWriter();

            // XMLをきれいに出力したい
            var settings = new XmlWriterSettings()
            {
                Encoding = new UTF8Encoding(false),
                Indent = true,
                NewLineOnAttributes = true,
            };
            var xwt = XmlWriter.Create(wt, settings);

            dcs.WriteObject(xwt, ex);

            // 使った後はCloseするよ
            xwt.Close();
            wt.Close();

            string xml = wt.ToString();

            return xml;
        }

XMLに変換するのは1行で終わってるのだけど、その前準備がいろいろ必要。シリアライザーがXMLライターに出力して、XMLライターはStringライターに出力してという3段構えになっていて、なんとも大袈裟だけど、フレームワークなので仕方がない。

あと、JSONは1行になって大変読みにくかったが、XMLライターには清書オプションがあったので、割と読める。


JSONでは困ったことになっていたことが、XMLでは割と解決している。
  • enumは「mm以上」のようなテキストで保存される(JSONは整数値だった)
  • 自分のクラスがわかる。ルートに「mm論理式」とある。
これならXMLを使う方がよさそう。

(5)XMLテキストからオブジェクトを復元する
これも、シリアライザー→XMLリーダー→Stringリーダーの3段構え。大袈裟だけど(以下略)。

internal static mm論理式 get論理式(string xml)
        {
            var dcs = new DataContractSerializer(typeof(mm論理式));

            StringReader rd = new StringReader(xml);

            var xrd = XmlReader.Create(rd);

            object obj = dcs.ReadObject(xrd);

            // 使った後はCloseするよ
            xrd.Close();
            rd.Close();

            return (mm論理式) obj;
        }

復元するクラスを「mm論理式」と決め打ちにしているのは実際の運用ではNGだけど、これはお試し用なので気にしない。デバッガーで見ると、オブジェクトが復元されていた。


エンコードの問題(2017/10/16追記)

オブジェクトを保存したXMLの1行目を見ると、、、

<?xml version="1.0" encoding="utf-16"?>

なぜかエンコードが「uft-16」になっている。これはStringWriterのエンコードが「utf-16」で固定だかららしい(設定で変更できない)。しかし、XMLの文字列はutf-8なのだよね?

気持ち悪いので「utf-8」に変えたいところだが、ではなぜ「utf-8」なのかと自問すると回答が返ってこないので、もう「utf-16」にあわせることにする。

(4)の設定をしているところで、utf-8を指定していたのをUnicodeに変える。

// XMLをきれいに出力したい
            var settings = new XmlWriterSettings()
            {
                Encoding = Encoding.Unicode,
                Indent = true,
                NewLineOnAttributes = true,
            };

将来、utf-8がよいと気が変わったら、何か考えよう。StringWriterの代わりにMemoryStreamを使うとか?

あと、XMLを直接ファイルに書き込むのであれば、XmlWriter.Createメソッドの第1引数にファイルのパスを指定すれば、何も悩まずにutf-8で保存される。

var xwt = XmlWriter.Create(path, settings);

未解決問題

「Type colType;」メンバーを保存できないのはXMLでもダメだった。これについてはあきらめかな。

コメント

このブログの人気の投稿

varchar をデータ型 numeric に変換中に、算術オーバーフロー エラーが発生しました。