これは、型情報が出力に埋め込まれていない宣言型シリアル化の固有の制限にすぎません。
変換しようとしてオン<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 { }
set { }
}
これはメンテナンスの悪夢になる可能性があります...
IXmlSerializableを実装する
あなたが物事を完全に制御するという点で最初のオプションに似ていますが
- 長所
- 厄介な「偽の」プロパティがぶら下がっていません。
- 柔軟性/バージョン管理を追加してxml構造と直接対話できます
- 短所
- クラスの他のすべてのプロパティのホイールを再実装する必要がある場合があります
努力の重複の問題は最初のものと同様です。
折り返しタイプを使用するようにプロパティを変更します
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();
if (type == "null")
return;
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のアイデアを最初の手法の「バッキング」プロパティにマージすることかもしれません。このようにして、うなり声の仕事のほとんどはあなたのために行われますが、クラスの消費者は内省との混乱を超えて影響を受けることはありません。