[解決済み] インターフェイスプロパティのXMLシリアライゼーション
質問
オブジェクトをXMLシリアライズしたいのですが、そのオブジェクトは(特に)プロパティタイプが IModelObject (これはインターフェースです) を持つオブジェクトをXMLシリアライズしたいです。
public class Example
{
public IModelObject Model { get; set; }
}
このクラスのオブジェクトをシリアライズしようとすると、以下のエラーが発生します。
"Example型のメンバーExample.Modelはインターフェースであるため、シリアライズできません。
インターフェイスがシリアライズできないことが問題であることは理解しました。しかし,具体的な モデル オブジェクトの型は実行時まで不明です。
を置き換えて IModelObject インターフェースを抽象型または具象型に置き換え、XMLInclude で継承を使用することは可能ですが、醜い回避方法のように思われます。
何か提案はありますか?
どのように解決するのですか?
これは単に、型情報が出力内に埋め込まれていない宣言的シリアライズの固有の制限です。
変換しようとする際に
<Flibble Foo="10" />
に戻そうとすると
public class Flibble { public object Foo { get; set; } }
シリアライザは、int、string、double(または他の何か)であるべきかをどのように知るのでしょうか...。
これを動作させるには、いくつかの選択肢がありますが、実行時まで本当にわからないのであれば、最も簡単なのは XmlAttributeOverrides .
悲しいことに、これはインターフェースではなく、基底クラスでしか動作しません。 そこでできることは、あなたのニーズには十分でないプロパティを無視することです。
もし本当にインターフェイスのままでなければならないのであれば、3つの選択肢があります。
隠して、別のプロパティで処理する
醜く、不快なボイラープレートと多くの繰り返しがありますが、クラスのほとんどの消費者はこの問題に対処する必要がありません。
[XmlIgnore()]
public object Foo { get; set; }
[XmlElement("Foo")]
[EditorVisibile(EditorVisibility.Advanced)]
public string FooSerialized
{
get { /* code here to convert any type in Foo to string */ }
set { /* code to parse out serialized value and make Foo an instance of the proper type*/ }
}
これはメンテナンスの悪夢になりそうです...。
IXmlSerializable の実装
最初の選択肢と同様、物事を完全に制御することができますが
-
長所
- 厄介な「偽」プロパティがうろつくことがない。
- xml 構造を直接操作することができ、柔軟性やバージョンアップが可能です。
-
短所
- クラスの他のすべてのプロパティのホイールを再実装しなければならないかもしれません。
努力の重複の問題は、1番目と同様です。
ラッピングタイプを使用するようにプロパティを変更する
public sealed class XmlAnything<T> : IXmlSerializable
{
public XmlAnything() {}
public XmlAnything(T t) { this.Value = t;}
public T Value {get; set;}
public void WriteXml (XmlWriter writer)
{
if (Value == null)
{
writer.WriteAttributeString("type", "null");
return;
}
Type type = this.Value.GetType();
XmlSerializer serializer = new XmlSerializer(type);
writer.WriteAttributeString("type", type.AssemblyQualifiedName);
serializer.Serialize(writer, this.Value);
}
public void ReadXml(XmlReader reader)
{
if(!reader.HasAttributes)
throw new FormatException("expected a type attribute!");
string type = reader.GetAttribute("type");
reader.Read(); // consume the value
if (type == "null")
return;// leave T at default value
XmlSerializer serializer = new XmlSerializer(Type.GetType(type));
this.Value = (T)serializer.Deserialize(reader);
reader.ReadEndElement();
}
public XmlSchema GetSchema() { return(null); }
}
これを使うと、(プロジェクトPでは)次のようなことになります。
public namespace P
{
public interface IFoo {}
public class RealFoo : IFoo { public int X; }
public class OtherFoo : IFoo { public double X; }
public class Flibble
{
public XmlAnything<IFoo> Foo;
}
public static void Main(string[] args)
{
var x = new Flibble();
x.Foo = new XmlAnything<IFoo>(new RealFoo());
var s = new XmlSerializer(typeof(Flibble));
var sw = new StringWriter();
s.Serialize(sw, x);
Console.WriteLine(sw);
}
}
を与える。
<?xml version="1.0" encoding="utf-16"?>
<MainClass
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Foo type="P.RealFoo, P, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<RealFoo>
<X>0</X>
</RealFoo>
</Foo>
</MainClass>
これは明らかにクラスのユーザにとってより面倒ですが、多くの定型句を回避することができます。
幸せな媒体は、XmlAnythingのアイデアを最初のテクニックの'backing'プロパティにマージすることでしょう。この方法では、大変な作業のほとんどはあなたのために行われますが、クラスの消費者は、introspectionで混乱する以上の影響を受けません。
関連
-
[解決済み] [Entity Framework 4.1でエンティティに関連オブジェクトを追加する際に、エンティティオブジェクトをIEntityChangeTracker.の複数のインスタンスから参照できない。
-
[解決済み】C#はJavaのcharAt()と同等?)
-
[解決済み】WSACancelBlockingCallの例外について
-
[解決済み】Microsoft.Extensions.LoggingからILoggerを解決することができない
-
[解決済み】スレッド終了またはアプリケーションの要求により、I/O操作が中断されました。
-
[解決済み] C#のオートプロパティに初期値を与える最良の方法は何ですか?
-
[解決済み] IDisposable インターフェースの正しい使用法
-
[解決済み] 特定のプロパティに対するLINQのDistinct()
-
[解決済み] JavaScriptSerializer - 列挙型を文字列としてJSONシリアライズする
-
[解決済み】TをEnumに拘束するGenericメソッドの作成
最新
-
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 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】"出力タイプがクラスライブラリのプロジェクトは直接起動できない"
-
[解決済み】Ajax処理で「無効なJSONプリミティブ」と表示される件
-
[解決済み] [Entity Framework 4.1でエンティティに関連オブジェクトを追加する際に、エンティティオブジェクトをIEntityChangeTracker.の複数のインスタンスから参照できない。
-
[解決済み】Swashbuckle/Swagger + ASP.Net Core: "Failed to load API definition" (API定義の読み込みに失敗しました
-
[解決済み】Moqを使用してメソッド呼び出しを検証する
-
[解決済み】OnCollisionEnter2Dが実行されない?
-
[解決済み】2つ(またはそれ以上)のリストを1つに統合する(C# .NETで
-
[解決済み】「namespace」なのに「type」のように使われる。
-
[解決済み] 汎用クラスやメソッドのメンバからTの型を取得する方法
-
[解決済み] XmlInclude または SoapInclude 属性を使用して、静的に知られていない型を指定します。