2015-11-26 24 views
5

Sto provando a serializzare in XML/deserializzare un oggetto in C#. Il problema è che questo oggetto è di un tipo che non è stato dichiarato nello stesso assembly del codice che sta invocando la serializzazione. Invece, proviene da un assembly caricato dinamicamente in runtime, quindi non è noto al momento della compilazione per il codice che sta invocando la serializzazione.: impossibile serializzare un oggetto proveniente da un altro assieme

Il tipo che sto cercando di serializzare è questo:

//Assembly = P.dll 
namespace EDFPlugin.Plugin1 
{ 
    [Serializable] 
    [XmlRoot(Namespace = "EDFPlugin.Plugin1")] 
    [XmlInclude(typeof(Options))] 
    public class Options 
    { 
     private string _username; 
     private string _password; 

     public string Username { 
      get { return _username; } 
      set { _username = value;} 
     } 

     public string Password 
     { 
      get { return _password; } 
      set { _password = value; } 
     } 
    } 
} 

Come ho detto prima, il codice che sto usando per cercare di serializzare/deserializzare l'oggetto si trova in un assembly che non lo fa conoscere il tipo Options al momento della compilazione (poiché carica in modo dinamico P.dll in fase di esecuzione). Tuttavia, sono riuscito a serializzare il tipo correttamente, utilizzando questo codice:

//Assembly = A.exe (doesn't know about P.dll at compile time) 
object value = GetOptions() //the actual type returned by this method is EDFPlugin.Plugin1.Options !! 
XmlSerializer valueSerializer = new XmlSerializer(value.GetType()); 
valueSerializer.Serialize(writer, value); 

in fondo, come si può vedere, chiamando GetType() posso aggirare il problema di non avere conoscenza del tipo Options al momento della compilazione, tutto funziona bene

Il problema sorge quando si tenta di deserializzare:

//Assembly = A.exe (doesn't know about P.dll at compile time) 
XmlSerializer valueSerializer = new XmlSerializer(typeof(object)); //have to use object, as I don't know the type in question... 
object value = valueSerializer.Deserialize(reader); //throws exception 

Dal momento che non conosco il tipo in questione in anticipo, io in fondo non può impostare correttamente il XmlSerializer. Utilizzando un generico object, come mostrato nel codice sopra, genera un'eccezione:

"<Options xmlns='EDFPlugin.Plugin1'> was not expected." 

Come posso risolvere questo problema?

+0

È necessario definire il tipo di corrispondenza (non necessariamente lo stesso, ma il nome e le proprietà ricercate devono essere presentate per la deserializzazione corretta), vedere [domanda correlata] (http://stackoverflow.com/q/26368990/1997232). La deserializzazione è tutta una questione di riflessione, se il tipo non può essere trovato con qualsiasi mezzo non può essere deserializzato. Dovrai * mimare * 'EDFPlugins.Plagin1' in 'A.exe'. – Sinatr

+0

@Sinatr: grazie per le informazioni. Sfortunatamente, non posso farlo. L'idea è che il mio programma carichi dinamicamente una serie di plugin, che possono esporre oggetti opzioni serializzabili come quello che mostro nella domanda. Il mio programma dovrebbe essere in grado di salvare/caricare automaticamente queste opzioni. Tuttavia, non ho alcuna conoscenza di quali campi un certo plugin potrebbe esporre in un oggetto opzioni –

+1

Ho pensato che stai parlando di deserializzazione quando 'p.dll' non è ancora stato caricato. Se è caricato, ottenere il tipo da assembly caricato (ignora come è caricato) non dovrebbe essere difficile (come per la risposta di @ Ksv3n). In caso di plugin si espongono alcune API in modo tale che le configurazioni vengano salvate dai plug-in (o in altro modo, il plug-in fornisca tutte le informazioni). Per esempio. crea il metodo 'GetTypeToSerialize()' che ciascun plugin deve implementare e puoi ottenere il tipo ora. – Sinatr

risposta

3

a.exe (non sa di P.dll al momento della compilazione)

Quindi, se a.exe sa in fase di esecuzione, dovreste essere in grado do caricare dinamicamente EDFPlugin.Plugin1

che ne dite:

XmlSerializer valueSerializer = new XmlSerializer(Type.GetType("EDFPlugin.Plugin1.Options")); 
object value = valueSerializer.Deserialize(reader); 

Ma cosa succede se non so che typename sia?

Si consiglia di mettere un'interfaccia personalizzata per distinguere la classe di opzioni in un'altra classe, quindi sarà possibile filtrare in modo dinamico e caricarla con XmlSerializer.

public interface IAmPlugin 
{ 

} 

public class Options: IAmPlugin 
{ 
     ...... 
} 

Poi:

Assembly assembly = ... // Your Assemblie which contains plugin 

// XmlSerializer needs all possible types to Deserialize an interface 
var possibleTypes = assembly.GetTypes().Where(t => t.IsClass && t.IsAssignableFrom(typeof(IAmPlugin))).ToArray(); 

XmlSerializer serializer = new XmlSerializer(typeof(IAmPlugin), possibleTypes); 
object value = valueSerializer.Deserialize(reader); 

Questo presuppone che un vuoto costruttori pubblici sulla classe di opzioni.

Perché un'interfaccia invece di un attributo? Poiché XmlSerializer gestisce solo più tipi di interfaccia.

+0

Ma cosa succede se non conosco quel nome tipografico? L'idea è che ho una serie di plugin che possono esporre un oggetto serializzabile che il mio A.exe dovrebbe essere in grado di salvare/caricare. In questo caso è il tipo di Opzioni, ma potrebbe essere qualsiasi altra cosa, non so in anticipo. Pensavo che il tag [XmlRoot (Namespace = "EDFPlugin.Plugin1")] si sarebbe occupato di quello (in realtà scrive lo spazio dei nomi nell'XML) ma apparentemente no. –

+0

Ho fatto un aggiornamento. – Ksv3n

+1

Grazie, non sapevo che potresti specificare più tipi da "provare" con XmlSerializer! –