XmlSerializer: si è verificato un errore durante la riflessione del tipo
-
09-06-2019 - |
Domanda
Utilizzando C# .NET 2.0, ho una classe di dati composita che ha il file [Serializable]
attribuire su di esso.Sto creando un XMLSerializer
class e passandolo al costruttore:
XmlSerializer serializer = new XmlSerializer(typeof(DataClass));
Ricevo un'eccezione che dice:
Si è verificato un errore durante la riflessione del tipo.
All'interno della classe dati c'è un altro oggetto composito.Anche questo deve avere il file [Serializable]
o avendolo sull'oggetto in alto, lo applica ricorsivamente a tutti gli oggetti all'interno?
Soluzione
Guarda l'eccezione interiore che stai ottenendo.Ti dirà quale campo/proprietà ha problemi di serializzazione.
È possibile escludere campi/proprietà dalla serializzazione xml decorandoli con il file [XmlIgnore]
attributo.
Non lo penso XmlSerializer
utilizza il [Serializable]
attributo, quindi dubito che sia questo il problema.
Altri suggerimenti
Ricorda che le classi serializzate devono avere valori predefiniti (ad es.costruttori senza parametri).Se non hai alcun costruttore, va bene;ma se hai un costruttore con un parametro, dovrai aggiungere anche quello predefinito.
Ho avuto un problema simile e si è scoperto che il serializzatore non riusciva a distinguere tra 2 classi che avevo con lo stesso nome (una era una sottoclasse dell'altra).L'eccezione interna assomigliava a questa:
Entrambi i tipi "BaseNamespace.Class1" e "BaseNamespace.SubNamespace.Class1" utilizzano il nome del tipo XML, "Class1", dallo spazio dei nomi ''.Utilizzare gli attributi XML per specificare un nome XML e/o uno spazio dei nomi univoci per il tipo.
Dove BaseNamespace.SubNamespace.Class1 è una sottoclasse di BaseNamespace.Class1.
Quello che dovevo fare era aggiungere un attributo a una delle classi (l'ho aggiunto alla classe base):
[XmlType("BaseNamespace.Class1")]
Nota:Se hai più livelli di classi devi aggiungere un attributo anche a loro.
Tieni presente anche questo XmlSerializer
non è possibile serializzare proprietà astratte..Vedi la mia domanda Qui (a cui ho aggiunto il codice della soluzione).
Motivi più comuni da me:
- the object being serialized has no parameterless constructor
- the object contains Dictionary
- the object has some public Interface members
Tutti gli oggetti nel grafico di serializzazione devono essere serializzabili.
Da XMLSerializer
è una scatola nera, controlla questi collegamenti se desideri eseguire ulteriormente il debug del processo di serializzazione.
Modifica del punto in cui XmlSerializer restituisce gli assembly temporanei
COME:Eseguire il debug in un assembly generato da .NET XmlSerializer
Se è necessario gestire attributi specifici (ad es.Dizionario o qualsiasi classe), puoi implementare il file IXmlSerializzabile interfaccia, che ti consentirà maggiore libertà al costo di una codifica più dettagliata.
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
}
C'è un interessante articolo, che mostrano un modo elegante per implementare un modo sofisticato per "estendere" XmlSerializer.
L'articolo dice:
IXmlSerializable è trattato nella documentazione ufficiale, ma la documentazione afferma che non è destinato all'uso pubblico e non fornisce informazioni oltre a ciò.Ciò indica che il team di sviluppo voleva riservarsi il diritto di modificare, disabilitare o addirittura rimuovere completamente questo gancio di estensibilità in futuro.Tuttavia, finché sei disposto ad accettare questa incertezza e ad affrontare possibili cambiamenti in futuro, non c'è motivo per cui non puoi trarne vantaggio.
Per questo motivo, suggerisco di implementare il tuo IXmlSerializable
classi, per evitare implementazioni troppo complicate.
...potrebbe essere semplice implementare la nostra abitudine XmlSerializer
classe utilizzando la riflessione.
Ho scoperto che la classe Dictionary in .Net 2.0 non è serializzabile utilizzando XML, ma serializza bene quando viene utilizzata la serializzazione binaria.
Ho trovato una soluzione Qui.
Recentemente l'ho ottenuto in una classe parziale di riferimento web quando ho aggiunto una nuova proprietà.La classe generata automaticamente aggiungeva i seguenti attributi.
[System.Xml.Serialization.XmlElementAttribute(Order = XX)]
Avevo bisogno di aggiungere un attributo simile con un ordine superiore all'ultimo nella sequenza generata automaticamente e questo ha risolto il problema.
Anch'io pensavo che l'attributo Serializable dovesse essere sull'oggetto ma, a meno che non sia un totale noob (sono nel bel mezzo di una sessione di codifica a tarda notte), i seguenti lavori dal 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();
}
}
}
Immagino che XmlSerializer utilizzi la riflessione sulle proprietà pubbliche.
Ho appena ricevuto lo stesso errore e ho scoperto che una proprietà di tipo IEnumerable<SomeClass>
era il problema.Sembra che IEnumerable
non può essere serializzato direttamente.
Invece, si potrebbe usare List<SomeClass>
.
Ho avuto una situazione in cui l'ordine era lo stesso per due elementi di fila
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "SeriousInjuryFlag")]
....qualche codice...
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "AccidentFlag")]
Quando ho modificato il codice per incrementare l'ordine di uno per ogni nuova proprietà nella classe, l'errore è scomparso.
Tieni inoltre presente che non puoi serializzare i controlli dell'interfaccia utente e che qualsiasi oggetto che desideri passare negli appunti deve essere serializzabile altrimenti non può essere passato ad altri processi.
Ho usato il NetDataSerialiser
Classe per serializzare le mie lezioni di dominio. Classe NetDataContractSerializer.
Le classi di dominio sono condivise tra client e server.
[System.Xml.Serialization.XmlElementAttribute("strFieldName", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
//O
Xmlignore] string [] strfielsname {get; set;}
Ho avuto lo stesso problema e nel mio caso l'oggetto aveva una ReadOnlyCollection.Una raccolta deve implementare il metodo Add per essere serializzabile.