web-dev-qa-db-ja.com

XmlIncludeまたはSoapInclude属性を使用して、静的に認識されていないタイプを指定します

.NETのXmlSerializerを操作するときに、非常に奇妙な問題があります。

以下のクラスの例をご覧ください。

public class Order 
{
    public PaymentCollection Payments { get; set; }

    //everything else is serializable (including other collections of non-abstract types)
}

public class PaymentCollection : Collection<Payment>
{
}

public abstract class Payment 
{
    //abstract methods
}

public class BankPayment : Payment
{
    //method implementations
}

私の知る限り、シリアライザが派生型InvalidOperationExceptionを知らないことに起因するPaymentを解決するための3つの異なる方法があります。

1。 XmlIncludeクラス定義へのPaymentの追加:

これは、私が制御できない外部参照としてすべてのクラスが含まれているため不可能です。

2。 XmlSerializerインスタンスの作成中に派生型の型を渡す

動作しません。

3。ターゲットプロパティのXmlAttributeOverridesを定義して、プロパティのデフォルトのシリアル化をオーバーライドする( this SO post

また、動作しません(XmlAttributeOverrides初期化が続きます)。

Type bankPayment = typeof(BankPayment);

XmlAttributes attributes = new XmlAttributes();
attributes.XmlElements.Add(new XmlElementAttribute(bankPayment.Name, bankPayment));

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
overrides.Add(typeof(Order), "Payments", attributes);

次に、適切なXmlSerializerコンストラクターが使用されます。

注:は機能しませんInvalidOperationExceptionBankPaymentは予期されていませんでした...)がスローされます。

誰もが主題にいくらか光を当てることができますか?どうすれば問題をさらにデバッグしてデバッグできますか?

81
lsoliveira

問題を解決しました。しばらく掘り下げた後、 this SO post が見つかりました。これはまったく同じ状況をカバーしています。それは私を正しい軌道に乗せました。

基本的に、XmlSerializerは、デフォルトの名前空間if派生クラスが追加の型として含まれていることを知る必要があります。これが発生しなければならない正確な理由はまだ不明ですが、それでもシリアル化は現在機能しています。

37
lsoliveira

これは私のために働いた:

[XmlInclude(typeof(BankPayment))]
[Serializable]
public abstract class Payment { }    

[Serializable]
public class BankPayment : Payment {} 

[Serializable]
public class Payments : List<Payment>{}

XmlSerializer serializer = new XmlSerializer(typeof(Payments), new Type[]{typeof(Payment)});
80
bizl

this に基づいて、クラスを変更する代わりに使用していたXmlSerializerのコンストラクターを変更することでこれを解決できました。

このようなものを使用する代わりに(他の回答で提案されています):

[XmlInclude(typeof(Derived))]
public class Base {}

public class Derived : Base {}

public void Serialize()
{
    TextWriter writer = new StreamWriter(SchedulePath);
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<Derived>));
    xmlSerializer.Serialize(writer, data);
    writer.Close();
}

これは私がしました:

public class Base {}

public class Derived : Base {}

public void Serialize()
{
    TextWriter writer = new StreamWriter(SchedulePath);
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<Derived>), new[] { typeof(Derived) });
    xmlSerializer.Serialize(writer, data);
    writer.Close();
}
0
derekantrican