.NETでのXMLシリアル化では、コンストラクタのextraTypes[]
パラメータを使用して多型オブジェクトを使用できます。 IXmlSerializable
を実装するタイプのXMLシリアル化のカスタマイズも可能です。多態型とIXmlSerializable
しかし、私はこれらの2つの機能を組み合わせることができないんだ - この最小限の例で示されているように:
型CsFoo.CustomSerializable:
using System; using System.IO; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; namespace CsFoo { public class CustomSerializable : IXmlSerializable { public XmlSchema GetSchema() { return null; } public void ReadXml(XmlReader xr) { } public void WriteXml(XmlWriter xw) { } } class CsFoo { static void Main() { XmlSerializer xs = new XmlSerializer( typeof(object), new Type[] { typeof(CustomSerializable) }); xs.Serialize(new StringWriter(), new CustomSerializable()); } }
最後の行は、このメッセージで
System.InvalidOperationException
をスローしますこの文脈で パラメータとしてCsFoo.CustomSerializableを使用しないでください。 タイプ、またはクラスまたは構造体のメンバ、パラメータ、戻り値 タイプ、またはメンバをtyとして宣言する必要がありますpe CsFoo.CustomSerializable (これはオブジェクトではありません)。タイプCsFoo.CustomSerializable のオブジェクトは、ArrayListsなどの型指定されていないコレクションでは使用できません。動的に生成されたXMLアセンブリを通じてワタリ
、我々は最終的に呼び出すことにより、バック.NET標準ライブラリのコードに来る:
protected Exception CreateUnknownTypeException(Type type)
{
if (typeof(IXmlSerializable).IsAssignableFrom(type))
{
return new InvalidOperationException(
Res.GetString("XmlInvalidSerializable",
new object[] { type.FullName }));
}
// Rest omitted...
リフレクターショー:
はSystem.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(
String, String, Object, Boolean) : Void
ターンでは、これはにつながりますリソースXmlInvalidSerializable
は上記の文字列に対応しています。つまり、WriteTypedPrimitive
はIXmlSerializable
が好きではありません。
我々は非多型シリアライザを生成する場合、そのように:これは正しくIXmlSerializable
を扱う
System.Xml.Serialization.XmlSerializationWriter.WriteSerializable(
IXmlSerializable, String, String, Boolean) : Void
:
XmlSerializer xs = new XmlSerializer(typeof(CustomSerializable));
.NETはへの呼び出しを生成します。 .NETが多型の場合にこの関数を使用しない理由を誰かが知っていますか? XMLシリアライザが生成するC#を見ると、これは非常に簡単に行うことができます。ここで私はテストされていない溶液を用いて、XMLシリアライザから得たいくつかのコードです:
void Write1_Object(string n, string ns, global::System.Object o,
bool isNullable, bool needType)
{
if ((object)o == null)
{
if (isNullable) WriteNullTagLiteral(n, ns);
return;
}
if (!needType)
{
System.Type t = o.GetType();
if (t == typeof(global::System.Object))
{
}
>>> patch begin <<<
+ else if (typeof(IXmlSerializable).IsAssignableFrom(t))
+ {
+ WriteSerializable((System.Xml.Serialization.IXmlSerializable)
((global::CsFoo.CustomSerializable)o),
+ @"CustomSerializable", @"", true, true);
+ }
>>> patch end <<<
else
{
WriteTypedPrimitive(n, ns, o, true);
return;
}
}
WriteStartElement(n, ns, o, false, null);
WriteEndElement(o);
}
これは技術的な理由からか、単に機能の制限のために残されていますか?サポートされていない機能、または私のばかげた?私のintertubes Googleのスキルは私に失敗します。
ここで関連する質問がありました。「C# Xml-Serializing a derived class using IXmlSerializable」が最も関連性があります。それは私がそれが単に不可能であると信じさせる。
この場合、私の現在の考えは、ルートの基本クラスにデフォルトのIXmlSerializable
実装を注入することです。そして、すべてがIXmlSerializable
になり、.NETは文句を言うことはありません。私はRef @ ve.Emitを使用して、具体的な型ごとにReadXml
とWriteXml
のボディを拾い上げて、ライブラリ1を使った場合と同じように見えるXMLを生成することができます。
XMLシリアル化の問題に直面すると、「わかっていますが、Reflection.Emitを使用してコードを生成します」と思う人もいます。今、彼らには2つの問題があります。
P.S.注意;私は.NETのXMLシリアル化の代替案を認識しており、制限があることを知っています。私はまた、POCOを保存することは、抽象的なデータ型を扱うよりもはるかに簡単であることを知っています。しかし、私は古いコードがたくさんあり、既存のXMLスキーマのサポートが必要です。
私はこれがSomeOtherXML
、YAML
、XAML
、ProtocolBuffers
、DataContract
、RandomJsonLibrary
、Thrift
、またはあなたのMorseCodeBasedSerializeToMp3
ライブラリ内がいかに簡単であるかを示す応答を感謝しながら、そう - 私は何を期待してることで、 - ちょっと私は何かを学ぶかもしれませんXMLシリアライザの回避策(解決策ではない場合)
とにかく、かなり遅れていますが、IXmlSerializableの場合は余分な種類のソリューションが私のために機能しません。しかし、[このアプローチ](http://www.softwarerockstar.com/2006/12/using-ixmlserializable-to-overcome-not-expected-error-on-derived-classes/)は、デシリアライズされたクラスプロパティクラス(!)とは異なるため、作成する正しい型を見つけるカスタムロジックをそのように実装できます。 – Vlad
もう一つの解決策があります(ここではhttps://connect.microsoft.com/VisualStudio/feedback/details/422577/incorrect-deserialization-of-polymorphic-type-that-implements-ixmlserializable)( 'XmlSchemaProvider'属性を使って) .net型にxml型をバインドする)が、コードが不足していて、私はその考え方を働かせることができませんでした。誰でも? – Vlad