2012-08-09 130 views
66

Tengo un problema muy extraño al trabajar con .NET XmlSerializer.Utilice el atributo XmlInclude o SoapInclude para especificar tipos que no se conocen de forma estática

tomar las siguientes clases de ejemplo:

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 
} 

yo sepa, hay tres métodos diferentes para resolver el InvalidOperationException que es causado por el serializador no saber acerca de los tipos derivados de Payment.

1. Adición de XmlIncludePayment a la definición de clase:

Esto no es posible debido a todas las clases que se incluyen como referencias externas sobre las cuales no tengo el control de.

2. Pasando tipos los tipos derivados durante la creación de la instancia XmlSerializer

no funciona.

3. Definir XmlAttributeOverrides de la propiedad de destino con el fin de anular la serialización por defecto de la propiedad (como se explica en this SO post)

tampoco funciona (XmlAttributeOverrides inicialización sigue).

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

Se usará entonces el constructor apropiado XmlSerializer.

NOTA: por no funciona me refiero a la InvalidOperationException (BankPayment no se esperaba ...) se lanza.

¿Alguien puede arrojar algo de luz sobre el tema? ¿Cómo se podría seguir y depurar el problema más?

Respuesta

29

Acabo de solucionar el problema. Después de buscar por un tiempo más, encontré this SO post que cubre exactamente la misma situación. Me puso en el camino correcto.

Básicamente, el XmlSerializer necesita saber el espacio de nombre predeterminado si las clases derivadas se incluyen como tipos adicionales. Todavía se desconoce el motivo exacto por el que esto tiene que pasar, pero, aún así, la serialización está funcionando ahora.

63

Esto funcionó para mí:

[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

Así que el tipo base tiene que saber todas sus implementaciones? Esto no parece una muy buena solución. ¿No hay otra manera? –

+1

@AlexanderStolz para la implementación genérica que pasa el nuevo tipo al crear el objeto XmlSerializable es la mejor solución. Como se menciona http://stackoverflow.com/a/2689660/698127 – Aamol

Cuestiones relacionadas