XmlSerializer: se produjo un error al reflejar el tipo

332

Usando C # .NET 2.0, tengo una clase de datos compuestos que tiene el [Serializable]atributo. Estoy creando una XMLSerializerclase y pasando eso al constructor:

XmlSerializer serializer = new XmlSerializer(typeof(DataClass));

Recibo una excepción que dice:

Se produjo un error al reflejar el tipo.

Dentro de la clase de datos hay otro objeto compuesto. ¿Esto también necesita tener el [Serializable]atributo, o al tenerlo en el objeto superior, lo aplica recursivamente a todos los objetos dentro?

leora
fuente

Respuestas:

413

Mire la excepción interna que está recibiendo. Le indicará qué campo / propiedad tiene problemas para serializar.

Puede excluir campos / propiedades de la serialización xml al decorarlos con el [XmlIgnore]atributo.

XmlSerializerno usa el [Serializable]atributo, así que dudo que ese sea el problema.

Lamar
fuente
11
Mi objeto tenía un campo Uri, lo que causó esta excepción; la clase Uri no tiene un constructor sin parámetros. Gracias por el consejo.
Ford
10
Encontré esto con una búsqueda en Google: mi problema particular era tener una propiedad en mi clase "para ser serializado" como IListcuando era necesario List.
Paul Aldred-Bann
77
¿Cómo se ve una "excepción interna"?
David
77
o agregue '@exception' a un reloj
arolson101
19
Gracias, esta respuesta me ayudó. Inicialmente miré la excepción interna, y solo vi mencionar a la clase principal. Pero me di cuenta de que podía profundizar en las inexcepciones de las inncepciones, y finalmente, 5 niveles más abajo, encontré el problema. Tenía clases que eran conflictivas. Gracias.
Louis van Tonder
111

Recuerde que las clases serializadas deben tener constructores predeterminados (es decir, sin parámetros). Si no tienes ningún constructor, está bien; pero si tiene un constructor con un parámetro, también deberá agregar el predeterminado.

Jeremy McGee
fuente
44
¡Gracias por el recordatorio! Odio que este sea un error de tiempo de ejecución con poca explicación.
Jared Updike
Sigo cometiendo este error una y otra vez. gracias por recordarme que use un constructor sin parámetros ^^
aZtraL-EnForceR
25

Tuve un problema similar, y resultó que el serializador no podía distinguir entre 2 clases que tenía con el mismo nombre (una era una subclase de la otra). La excepción interna se veía así:

'Tipos BaseNamespace.Class1' y 'BaseNamespace.SubNamespace.Class1' usan el nombre de tipo XML, 'Class1', del espacio de nombres ''. Use atributos XML para especificar un nombre XML único y / o espacio de nombres para el tipo.

Donde BaseNamespace.SubNamespace.Class1 es una subclase de BaseNamespace.Class1.

Lo que necesitaba hacer era agregar un atributo a una de las clases (agregué a la clase base):

[XmlType("BaseNamespace.Class1")]

Nota: Si tiene más capas de clases, también debe agregarles un atributo.

Dennis Calla
fuente
Esto solucionó el problema para mí, gracias, +1; Tenía una configuración similar con varios objetos Processor *, cada uno con una clase interna de Config. El tiempo de ejecución no pudo distinguir entre SomeNS.Processor1.Config y SomeNS.Processor2.Config.
damix911
6

Las razones más comunes por mí:

 - the object being serialized has no parameterless constructor
 - the object contains Dictionary
 - the object has some public Interface members
Stefan Michev
fuente
5

Si necesita manejar atributos específicos (es decir, Diccionario, o cualquier clase), puede implementar la interfaz IXmlSerialiable , que le dará más libertad a costa de una codificación más detallada .

public class NetService : IXmlSerializable
{
    #region Data

        public string Identifier = String.Empty;

        public string Name = String.Empty;

        public IPAddress Address = IPAddress.None;
        public int Port = 7777;

    #endregion

    #region IXmlSerializable Implementation

        public XmlSchema GetSchema() { return (null); }

        public void ReadXml(XmlReader reader)
        {
            // Attributes
            Identifier = reader[XML_IDENTIFIER];
            if (Int32.TryParse(reader[XML_NETWORK_PORT], out Port) == false)
            throw new XmlException("unable to parse the element " + typeof(NetService).Name + " (badly formatted parameter " + XML_NETWORK_PORT);
            if (IPAddress.TryParse(reader[XML_NETWORK_ADDR], out Address) == false)
            throw new XmlException("unable to parse the element " + typeof(NetService).Name + " (badly formatted parameter " + XML_NETWORK_ADDR);
        }

        public void WriteXml(XmlWriter writer)
        {
            // Attributes
            writer.WriteAttributeString(XML_IDENTIFIER, Identifier);
            writer.WriteAttributeString(XML_NETWORK_ADDR, Address.ToString());
            writer.WriteAttributeString(XML_NETWORK_PORT, Port.ToString());
        }

        private const string XML_IDENTIFIER = "Id";

        private const string XML_NETWORK_ADDR = "Address";

        private const string XML_NETWORK_PORT = "Port";

    #endregion
}

Hay un artículo interesante , que muestra una forma elegante de implementar una forma sofisticada para "extender" el XmlSerializer.


El artículo dice:

IXmlSerializable está cubierto en la documentación oficial, pero la documentación indica que no está destinado al uso público y no proporciona información más allá de eso. Esto indica que el equipo de desarrollo quería reservar el derecho de modificar, deshabilitar o incluso eliminar completamente este enganche de extensibilidad en el futuro. Sin embargo, mientras esté dispuesto a aceptar esta incertidumbre y lidiar con posibles cambios en el futuro, no hay razón alguna para que no pueda aprovecharla.

Debido a esto, sugiero implementar sus propias IXmlSerializableclases, para evitar implementaciones demasiado complicadas.

... podría ser sencillo implementar nuestra XmlSerializerclase personalizada utilizando la reflexión.

Luca
fuente
4

Descubrí que la clase Diccionario en .Net 2.0 no se puede serializar usando XML, pero se serializa bien cuando se usa la serialización binaria.

Encontré un trabajo por aquí .

Sales de Charlie
fuente
3

Recientemente obtuve esto en una clase parcial de referencia web al agregar una nueva propiedad. La clase autogenerada estaba agregando los siguientes atributos.

    [System.Xml.Serialization.XmlElementAttribute(Order = XX)]

Necesitaba agregar un atributo similar con un orden mayor que el anterior en la secuencia generada automáticamente y esto me lo solucionó.

LepardUK
fuente
3

Acabo de recibir el mismo error y descubrí que una propiedad de tipo IEnumerable<SomeClass>era el problema. Parece que IEnumerableno se puede serializar directamente.

En cambio, uno podría usar List<SomeClass>.

jkokorian
fuente
2

También pensé que el atributo Serializable tenía que estar en el objeto, pero a menos que sea un novato completo (estoy en medio de una sesión de codificación nocturna) los siguientes trabajos del SnippetCompiler :

using System;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using System.Xml.Serialization;

public class Inner
{
    private string _AnotherStringProperty;
    public string AnotherStringProperty 
    { 
      get { return _AnotherStringProperty; } 
      set { _AnotherStringProperty = value; } 
    }
}

public class DataClass
{
    private string _StringProperty;
    public string StringProperty 
    { 
       get { return _StringProperty; } 
       set{ _StringProperty = value; } 
    }

    private Inner _InnerObject;
    public Inner InnerObject 
    { 
       get { return _InnerObject; } 
       set { _InnerObject = value; } 
    }
}

public class MyClass
{

    public static void Main()
    {
        try
        {
            XmlSerializer serializer = new XmlSerializer(typeof(DataClass));
            TextWriter writer = new StreamWriter(@"c:\tmp\dataClass.xml");
            DataClass clazz = new DataClass();
            Inner inner = new Inner();
            inner.AnotherStringProperty = "Foo2";
            clazz.InnerObject = inner;
            clazz.StringProperty = "foo";
            serializer.Serialize(writer, clazz);
        }
        finally
        {
            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }
    }

}

Me imagino que XmlSerializer está utilizando la reflexión sobre las propiedades públicas.

Darren
fuente
1

Tuve una situación en la que la Orden era la misma para dos elementos seguidos

[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "SeriousInjuryFlag")]

.... algún código ...

[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "AccidentFlag")]

Cuando cambié el código para incrementar el orden en uno para cada nueva Propiedad en la clase, el error desapareció.

Jeremy Brown
fuente
1

Recibía el mismo error cuando creé una propiedad que tenía un tipo de datos - Type. En esto, recibí un error: hubo un error al reflejar el tipo. Seguí comprobando la 'InnerException' de cada excepción desde el muelle de depuración y obtuve el nombre de campo específico (que era Type) en mi caso. La solución es la siguiente:

    [XmlIgnore]
    public Type Type { get; set; }
Iqra.
fuente
0

También tenga en cuenta que no puede serializar los controles de la interfaz de usuario y que cualquier objeto que desee pasar al portapapeles debe ser serializable; de ​​lo contrario, no se puede pasar a otros procesos.

Phil Wright
fuente
0

He estado usando la NetDataSerialiserclase para serializar mis clases de dominio. NetDataContractSerializer Class .

Las clases de dominio se comparten entre el cliente y el servidor.

Peter Mortensen
fuente
0

Tuve el mismo problema y en mi caso el objeto tenía una ReadOnlyCollection. Una colección debe implementar el método Add para ser serializable.

Dev curioso
fuente
Esta no es una respuesta adecuada a la pregunta. Ya hay otras 15 respuestas sobre esta pregunta. Si cree que su respuesta es mejor que las demás, debe proporcionar más detalles al respecto. Proporcionar algunos fragmentos de código y salida siempre ayuda a los usuarios. Antes de publicar sus respuestas, considere leer -> stackoverflow.com/help/how-to-answer
Amit Phaltankar
0

Tengo una solución ligeramente diferente a todo lo descrito aquí hasta ahora, así que para cualquier civilización futura, ¡aquí está la mía!

Había declarado un tipo de datos de "tiempo" ya que el tipo original era a TimeSpany posteriormente cambió a String:

[System.Xml.Serialization.XmlElementAttribute(DataType="time", Order=3)]

sin embargo, el tipo real era una cadena

public string TimeProperty {
    get {
        return this.timePropertyField;
    }
    set {
        this.timePropertyField = value;
        this.RaisePropertyChanged("TimeProperty");
    }
}

eliminando la DateTypepropiedad Xmlse puede serializar

[System.Xml.Serialization.XmlElementAttribute(Order=3)]
public string TimeProperty {
    get {
        return this.timePropertyField;
    }
    set {
        this.timePropertyField = value;
        this.RaisePropertyChanged("TimeProperty");
    }
}
chxzy
fuente
0
[System.Xml.Serialization.XmlElementAttribute("strFieldName", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]

O

[XmlIgnore]
string [] strFielsName {get;set;}
Kiran.Bakwad
fuente