Cómo agregar el atributo XmlInclude dinámicamente

Tengo las siguientes clases

[XmlRoot] public class AList { public List ListOfBs {get; set;} } public class B { public string BaseProperty {get; set;} } public class C : B { public string SomeProperty {get; set;} } public class Main { public static void Main(string[] args) { var aList = new AList(); aList.ListOfBs = new List(); var c = new C { BaseProperty = "Base", SomeProperty = "Some" }; aList.ListOfBs.Add(c); var type = typeof (AList); var serializer = new XmlSerializer(type); TextWriter w = new StringWriter(); serializer.Serialize(w, aList); } } 

Ahora, cuando trato de ejecutar el código, recibí una InvalidOperationException en la última línea que decía:

No se esperaba el tipo XmlTest.C. Utilice el atributo XmlInclude o SoapInclude para especificar los tipos que no se conocen estáticamente.

Sé que agregar un atributo [XmlInclude (typeof (C))] con [XmlRoot] resolvería el problema. Pero quiero lograrlo dinámicamente. Porque en mi clase de proyecto C no se conoce antes de la carga. La clase C se está cargando como un complemento, por lo que no me es posible agregar el atributo XmlInclude allí.

Lo intenté también con

 TypeDescriptor.AddAttributes(typeof(AList), new[] { new XmlIncludeAttribute(c.GetType()) }); 

antes de

 var type = typeof (AList); 

pero no uso Todavía está dando la misma excepción.

¿Alguien tiene alguna idea sobre cómo lograrlo?

Dos opciones; el más simple (pero dando impar xml) es:

 XmlSerializer ser = new XmlSerializer(typeof(AList), new Type[] {typeof(B), typeof(C)}); 

Con salida de ejemplo:

       

El más elegante es:

 XmlAttributeOverrides aor = new XmlAttributeOverrides(); XmlAttributes listAttribs = new XmlAttributes(); listAttribs.XmlElements.Add(new XmlElementAttribute("b", typeof(B))); listAttribs.XmlElements.Add(new XmlElementAttribute("c", typeof(C))); aor.Add(typeof(AList), "ListOfBs", listAttribs); XmlSerializer ser = new XmlSerializer(typeof(AList), aor); 

Con salida de ejemplo:

     

En cualquier caso, debe almacenar en caché y volver a utilizar la instancia de ser ; de lo contrario, se producirá una hemorragia en la memoria de la comstackción dinámica.

Basándome en la primera respuesta de Marc (solo tengo que leer, por lo que no necesito evitar la salida extraña), utilizo una matriz de tipos más dinámica / genérica para dar cuenta de los tipos desconocidos, inspirados por este proyecto de código .

  public static XmlSerializer GetSerializer() { var lListOfBs = (from lAssembly in AppDomain.CurrentDomain.GetAssemblies() from lType in lAssembly.GetTypes() where typeof(B).IsAssignableFrom(lType) select lType).ToArray(); return new XmlSerializer(typeof(AList), lListOfBs); } 

(Probablemente podría hacerlo más eficiente, por ejemplo, usando una matriz de tipos estática o de solo lectura en lugar de una variable local. Eso evitaría usar Reflection varias veces. Pero no sé lo suficiente sobre cuándo se cargan los ensamblajes y las clases y propiedades Inicialízate, para saber si eso te meterá en problemas. Mi uso no es mucho, tomar el tiempo para investigar todo esto, así que uso la misma Reflexión varias veces.

Eche un vistazo a la documentación de XmlSerializer. Hay un constructor que espera tipos conocidos como el segundo parámetro. Eso debería funcionar bien para su caso de uso.

No creo que los atributos se puedan aplicar en tiempo de ejecución, ya que se usan para crear metadatos en el código CIL.