2012-08-09 9 views
66

Mam bardzo dziwny problem podczas pracy z .NET XmlSerializer.Użyj atrybutu XmlInclude lub SoapInclude, aby określić typy nieznane statycznie

podjąć następujące przykładowe zajęcia:

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 
} 

AFAIK, istnieją trzy różne sposoby, aby rozwiązać ten InvalidOperationException że to spowodowane serializer nie wiedząc o pochodnych typów Payment.

1. Dodanie XmlInclude definicji Payment klasy:

Nie jest to możliwe ze względu na wszystkie zajęcia zostały ujęte jako odniesień zewnętrznych, nad którymi nie mam kontroli.

2. Przechodząc rodzajów rodzajów drewna podczas tworzenia instancji XmlSerializer

nie działa.

3. Definiowanie XmlAttributeOverrides dla właściwości docelowej, aby zastąpić domyślne serializacji na własność (jak wyjaśniono w this SO post)

również nie działa (XmlAttributeOverrides inicjalizacji poniżej).

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

Zostanie wówczas użyty odpowiedni konstruktor XmlSerializer.

UWAGA: przez nie działa Znaczy InvalidOperationException (BankPayment nie oczekiwano ...) jest rzucony.

Czy ktoś może rzucić nieco światła na ten temat? W jaki sposób obejść i dalej debugować problem?

Odpowiedz

29

Właśnie rozwiązałem problem. Po dłuższym okresie poszukiwań znalazłem this SO post, który obejmuje dokładnie tę samą sytuację. Sprawiło, że jestem na dobrej drodze.

Zasadniczo XmlSerializer musi wiedzieć domyślnej przestrzeni nazw jeśli klasy pochodne są włączone jako dodatkowych typów. Dokładny powód, dla którego to się wydarzyło, jest wciąż nieznany, ale serializacja działa.

63

Ten pracował dla mnie:

[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

Więc typ bazowy musi znać wszystkie jego implementacje? To nie wydaje się być bardzo dobrym rozwiązaniem. Czy nie ma innej drogi? –

+1

@AlexanderStolz do ogólnej implementacji przekazującej nowy typ podczas tworzenia obiektu XmlSerializable jest najlepszym rozwiązaniem. Jak wspomniano http://stackoverflow.com/a/2689660/698127 – Aamol