C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト


(過去ログ 152 を表示中)
■88339 / )  Re[3]: テーブルのデータをXMLファイルに出力したい
□投稿者/ 魔界の仮面弁士 (1787回)-(2018/08/22(Wed) 11:03:53)
2018/08/22(Wed) 11:36:49 編集(投稿者)

No88330 (河童 さん) に返信
> 確かにInvalidOperationExceptionというエラーが発生しています。

原因はここ。

var xmlSerializer1 = new XmlSerializer(typeof(m_User));
xmlSerializer1.Serialize(streamWriter, user);

「m_User」用のシリアライザを用いて、
「m_User」ではなく「List<m_User>」をシリアライズしていますよね。

ゆえに型変換エラー(InvalidCastException)の内部例外により、
処理失敗(InvalidOperationException)が通知されるわけです。

シリアライザの型を見直せば、一応解決します。
var xmlSerializer1 = new XmlSerializer(typeof(List<m_User>));



>>たとえば、m_User が「引数 0 個の public なコンストラクタ」をもっていない場合、
>>シリアライズ時に InvalidOperationException が発生したりしますね。
> ここはどういう意味でしょうか?

※私の発言に対する質問だったので、
 あえて解決済みマークは外して回答しています。


コンストラクタとは、ザックリ言えば、new で呼び出される処理のことです。
 m_User u = new m_User(); // 引数無しコンストラクタの呼び出し
 m_User u = new m_User("88330", "河童"); // 引数2つ(string, string)なコンストラクタの呼び出し

引数無しコンストラクタがない、または、あってもそれが private であるような場合、
デシリアライズ時にインスタンスを生成できず、InvalidOperationException の例外となります。

とはいえ今回の場合、new m_User() が使えるようになっているようなので、
コンストラクタの問題ではありません。


m_User u = new m_User() { user_id = "88330", user_name = "河童" };

var xmlSerializer1 = new XmlSerializer(typeof(m_User));
using (var streamWriter = new StreamWriter(xmlFile, false, Encoding.UTF8))
{
  // xmlSerializer1.Serialize(streamWriter, user); // これは NG
  xmlSerializer1.Serialize(streamWriter, u); // これは OK
  streamWriter.Flush();
}


上記は「m_User 用のシリアライザ」に「m_User 型のインスタンス」を
シリアライズ(永続化)させた例であり、下記の XML が生成されます。

<?xml version="1.0" encoding="utf-8"?>
<user xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <user_id>88330</user_id>
 <user_name>河童</user_name>
</user>


ちなみに、もしも XML宣言および名前空間が邪魔で、もっとシンプルに

<m_User>
 <user_id>88330</user_id>
 <user_name>河童</user_name>
</m_User>

と出力させたいのであれば、シリアライズ処理を下記のように書き換えることで対応できます。

using (var streamWriter = new StreamWriter(xmlFile, false, Encoding.UTF8))
using (var xmlWriter = XmlWriter.Create(streamWriter, new XmlWriterSettings() { OmitXmlDeclaration = true }))
{
 var ns = new XmlSerializerNamespaces();
 ns.Add("", "");
 xmlSerializer1.Serialize(xmlWriter, u, ns);
 streamWriter.Flush();
}


また、m_User クラスに属性指定を行うことで、XML の形式を変化させることもできます。

 [XmlRoot("user")]
 public class m_User
 {
  [XmlAttribute("id")] public string user_id { get; set; }
  [XmlText()] public string user_name { get; set; }
 }

上記の場合、シリアライズ結果がこのように変化し、さらにシンプルな XML となります。

<user id="88330">河童</user>



> データをXMLファイルに一度出力して、
> 別のDBと比較対象用に利用するつもりです。

データベースの比較を行うことが目的なのでしょうか。
XmlSerializer の使い方を学ぶことが目的なのでしょうか。
事前に定めておいた書式の XML ファイルを生成する(あるいは読み取る)ことが目的なのでしょうか。


> XMLファイルの書き出しと読込ができるようになりたいです。

XmlSerializer で永続化(シリアライズ)する場合、「XML として無効なデータ」が
存在するかどうかを気にしておいたほうが良いでしょう。

仮に m_User の内容が
 u = new m_User() { user_id = "88330", user_name = "河\u001a童" };
だったりすると、Serialize は成功しますが、Deserialize は失敗します。


また、現状の方法だと、
 public int user_id { get; set; }
なデータと
 public string user_id { get; set; }
なデータを区別してシリアライズすることが難しいという問題もあります。
返信 編集キー/


管理者用

- Child Tree -