[解決済み] XMLシリアライズと継承型
質問
私の 前の質問 私は私のオブジェクトモデルをXMLにシリアライズすることに取り組んできました。しかし、私は今問題に遭遇しました(驚きです!)。
私が抱えている問題は、抽象的な基本クラスタイプのコレクションを持っていて、それが具体的な派生タイプによって構成されていることです。
私は、関係するすべてのクラスに XML 属性を追加するだけでよく、すべてがうまくいくだろうと思いました。悲しいことに、そうではありません!
そこで、Google でいくつか調べてみたところ、次のことがわかりました。
なぜ
がうまくいかない理由がわかりました。その中で
は
XmlSerializer
は実際にはXMLとの間でオブジェクトを直列化するために巧妙なリフレクションを行っており、抽象的な型に基づいているため、それが一体何と話しているのかを理解することができません。
. 結構です。
確かに私は このページ をCodeProjectで見つけました。それは多くのことを助けるように見えますが(まだ完全に読んで/消費していません)、私はこの問題をStackOverflowのテーブルにも持って行きたいと思いました。
1 つ付け加えるとすれば、私は
はしないことです。
を実行したいと思います。
XmlInclude
のルートには入りたくありません。これには単純に多くのカップリングがあり、システムのこのエリアは重い開発中であるため、メンテナンスの頭痛の種になるでしょう!
どのように解決するのですか?
問題解決
さて、ようやくたどり着いたわけですが、(確かに ロット の助けを借りて)。 ここで !).
では、まとめます。
目標
- の下に行きたくなかった。 XmlInclude のルートは、メンテナンスの頭痛の種になるため、使いたくありませんでした。
- 解決策が見つかったら、他のアプリケーションに素早く実装できるようにしたいと思いました。
- 抽象的な型のコレクションは、個々の抽象的なプロパティと同様に使用することができます。
- 具象クラスで "特別な"ことをしなければならないことに煩わされたくなかったのです。
特定された問題点/注意点。
- XmlSerializer はかなりクールなリフレクションを行いますが、それは は非常に 抽象的な型に関しては制限されています (つまり、サブクラスではなく、抽象的な型そのもののインスタンスでのみ動作します)。
- Xml 属性デコレータは、XmlSerializer が検出したプロパティをどのように扱うかを定義します。物理的な型を指定することもできますが、その場合は タイトなカップリング クラスとシリアライザーの間にが発生します (良くないことです)。
- を実装したクラスを作成することで、独自のXmlSerializerを実装することができます。 IXmlSerializable .
解決策
ジェネリッククラスを作成しました。このクラスでは、ジェネリック型を作業対象となる抽象型として指定します。これにより、キャスティングをハードコーディングできるため、抽象型と具象型の間で "translate"できるようになりました (つまり、XmlSerializer ができる以上の情報を取得できるようになりました)。
次に、私は IXmlSerializable インターフェイスを実装します。これは非常に簡単ですが、シリアライズするときに、具象クラスの型を XML に書き込むことを確認する必要があり、シリアライズを解除するときにそれをキャストして戻すことができます。また、このクラスは 完全修飾 でなければならないことにも注意してください。もちろん、ここで起こる必要のある小さな型チェックや何かがあります。
XmlSerializerはキャストできないので、それを行うコードを提供する必要があり、暗黙の演算子はオーバーロードされます (こんなことができるなんて知らなかった!)。
AbstractXmlSerializerのコードはこれです。
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
namespace Utility.Xml
{
public class AbstractXmlSerializer<AbstractType> : IXmlSerializable
{
// Override the Implicit Conversions Since the XmlSerializer
// Casts to/from the required types implicitly.
public static implicit operator AbstractType(AbstractXmlSerializer<AbstractType> o)
{
return o.Data;
}
public static implicit operator AbstractXmlSerializer<AbstractType>(AbstractType o)
{
return o == null ? null : new AbstractXmlSerializer<AbstractType>(o);
}
private AbstractType _data;
/// <summary>
/// [Concrete] Data to be stored/is stored as XML.
/// </summary>
public AbstractType Data
{
get { return _data; }
set { _data = value; }
}
/// <summary>
/// **DO NOT USE** This is only added to enable XML Serialization.
/// </summary>
/// <remarks>DO NOT USE THIS CONSTRUCTOR</remarks>
public AbstractXmlSerializer()
{
// Default Ctor (Required for Xml Serialization - DO NOT USE)
}
/// <summary>
/// Initialises the Serializer to work with the given data.
/// </summary>
/// <param name="data">Concrete Object of the AbstractType Specified.</param>
public AbstractXmlSerializer(AbstractType data)
{
_data = data;
}
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null; // this is fine as schema is unknown.
}
public void ReadXml(System.Xml.XmlReader reader)
{
// Cast the Data back from the Abstract Type.
string typeAttrib = reader.GetAttribute("type");
// Ensure the Type was Specified
if (typeAttrib == null)
throw new ArgumentNullException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name +
"' because no 'type' attribute was specified in the XML.");
Type type = Type.GetType(typeAttrib);
// Check the Type is Found.
if (type == null)
throw new InvalidCastException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name +
"' because the type specified in the XML was not found.");
// Check the Type is a Subclass of the AbstractType.
if (!type.IsSubclassOf(typeof(AbstractType)))
throw new InvalidCastException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name +
"' because the Type specified in the XML differs ('" + type.Name + "').");
// Read the Data, Deserializing based on the (now known) concrete type.
reader.ReadStartElement();
this.Data = (AbstractType)new
XmlSerializer(type).Deserialize(reader);
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
// Write the Type Name to the XML Element as an Attrib and Serialize
Type type = _data.GetType();
// BugFix: Assembly must be FQN since Types can/are external to current.
writer.WriteAttributeString("type", type.AssemblyQualifiedName);
new XmlSerializer(type).Serialize(writer, _data);
}
#endregion
}
}
では、そこからどうやってXmlSerializerにデフォルトではなく、私たちのシリアライザーを使うように指示するのでしょうか?例えば、Xml属性のtypeプロパティ内で私たちの型を渡す必要があります。
[XmlRoot("ClassWithAbstractCollection")]
public class ClassWithAbstractCollection
{
private List<AbstractType> _list;
[XmlArray("ListItems")]
[XmlArrayItem("ListItem", Type = typeof(AbstractXmlSerializer<AbstractType>))]
public List<AbstractType> List
{
get { return _list; }
set { _list = value; }
}
private AbstractType _prop;
[XmlElement("MyProperty", Type=typeof(AbstractXmlSerializer<AbstractType>))]
public AbstractType MyProperty
{
get { return _prop; }
set { _prop = value; }
}
public ClassWithAbstractCollection()
{
_list = new List<AbstractType>();
}
}
ここでは、コレクションと単一のプロパティが公開されていることがわかります。 タイプ という名前のパラメータをXml宣言に追加するだけです。簡単ですね。:D
注:このコードを使用する場合、私は本当に賞賛を感謝します。また、より多くの人々をコミュニティに誘導するのに役立つでしょう :)
さて、しかし、すべての回答には長所と短所があったので、ここでの回答をどうするか迷っています。私は有用であると感じたものをアップモデし(そうでないものに悪気はありません)、私が評判を得たらこれを閉じます :)
面白い問題で、解決するのが楽しいです! :)
関連
-
[解決済み] SerializationとMarshalingの違いは何ですか?
-
[解決済み] C#のStringとstringの違いは何ですか?
-
[解決済み] serialVersionUIDとは何ですか、またなぜそれを使用する必要がありますか?
-
[解決済み] PHPでHTML/XMLをパースして処理する方法とは?
-
[解決済み] JavaScriptSerializer - 列挙型を文字列としてJSONシリアライズする
-
[解決済み] XMLの<![CDATA[]]>は何を意味するのですか?
-
[解決済み] XMLを解析して、特定のノード属性のインスタンスをカウントするには?
-
[解決済み] XML文書でエスケープする必要がある文字は何ですか?
-
[解決済み】type()とisinstance()の違いは何ですか?)
-
[解決済み] インターフェイスプロパティのXMLシリアライゼーション
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】指定されたキャストが有効でない?
-
[解決済み】C#におけるtypedefの等価性
-
[解決済み】「入力文字列が正しい形式ではありませんでした」エラーの解決方法は?[重複しています]。
-
[解決済み] [Solved] アセンブリ System.Web.Extensions dll はどこにありますか?
-
[解決済み] 'IEnumerable<SelectListItem>' 型の ViewData アイテムで、キーが国であるものは存在しない。
-
[解決済み】Entity FrameworkからのSqlException - セッション内で他のスレッドが動作しているため、新しいトランザクションは許可されません。
-
[解決済み】HRESULTからの例外:0x800A03ECエラー
-
[解決済み】5.7.57 SMTP - MAIL FROMエラー時に匿名メールを送信するためにクライアントが認証されない
-
[解決済み】WSACancelBlockingCallの例外について
-
[解決済み] XmlSerializer - 型の反映にエラーが発生しました。