2012-08-09 4 views
66

Ho un problema molto strano quando si lavora con .NET XmlSerializer.Utilizzare il XmlInclude o l'attributo SoapInclude per specificare i tipi che non sono noti staticamente

Prendere le seguenti classi di esempio:

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 
} 

per quanto ne so, ci sono tre diversi metodi per risolvere il InvalidOperationException che è causata dal serializzatore non sapere circa i tipi derivati ​​di Payment.

1. Aggiunta XmlInclude alla definizione Payment classe:

Questo non è possibile a causa di tutte le classi di essere inclusi come riferimenti esterni sui quali non ho alcun controllo su.

2. Passando tipi i tipi derivati ​​durante la creazione dell'istanza XmlSerializer

non funziona.

3. Definire XmlAttributeOverrides per la proprietà target per sovrascrivere serializzazione standard della struttura (come spiegato in this SO post)

Inoltre non funziona (XmlAttributeOverrides inizializzazione segue).

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); 

Il costruttore appropriato XmlSerializer verrà quindi utilizzato.

NOTA: per non funziona mi riferisco al InvalidOperationException (BankPayment non era previsto ...) viene generata.

Qualcuno può fare luce su questo argomento? Come si potrebbe procedere e risolvere il problema ulteriormente?

risposta

29

appena risolto il problema. Dopo scavare intorno per un tempo più lungo, ho trovato this SO post che copre la stessa situazione. Mi ha messo sulla strada giusta.

In sostanza, il XmlSerializer ha bisogno di conoscere il namespace di default se classi derivate sono inclusi come tipi aggiuntivi. Il motivo esatto per cui questo deve accadere è ancora sconosciuto, ma, ancora, la serializzazione sta lavorando ora.

63

Questo ha funzionato per me:

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

[Serializable] 
public class BankPayment : Payment {} 

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

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

Quindi il tipo di base ha bisogno di conoscere tutti i suoi implementazioni? Questa non sembra una buona soluzione. Non c'è altro modo? –

+1

@AlexanderStolz per implementazione generica passando nuovo tipo durante la creazione oggetto XmlSerializable è la soluzione migliore. Come accennato http://stackoverflow.com/a/2689660/698127 – Aamol