2014-07-14 12 views
6

Ho una lista di tipi che ho bisogno di salvare su file e leggerla dopo. Io uso DataContractSerializer ma ottengo un'eccezione durante la deserializzazione:Serialize/deserialize System.RuntimeType

Non riesci a trovare costruttore con argomenti (SerializationInfo, StreamingContext) in ISerializable "System.RuntimeType".

Ho aggiunto System.RuntimeType come un tipo noto al mio serializzatore, ma non è stato d'aiuto.

Ecco il codice dei miei due metodi

public static void SaveTypes(List<Type> types, string fileName) 
{ 
    Type rt = types[0].GetType(); 

    List<Type> knownTypes = new List<Type>() { rt }; //I get a List with System.RuntimeType item here 
    DataContractSerializer serializer = new DataContractSerializer(typeof(List<Type>), knownTypes); 
    XmlWriterSettings settings = new XmlWriterSettings(); 
    settings.Indent = true; 
    Stream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write); 
    using (XmlWriter xw = XmlWriter.Create(fs, settings)) 
     serializer.WriteObject(xw, types); 
} 

serializzazione sembra funzionare bene, e il file di output è ok, ma il problema inizia il deserializzazione:

public static object LoadTypes(string fileName) 
    { 
     Stream file = new FileStream(fileName, FileMode.Open, FileAccess.Read); 
     byte[] data = new byte[file.Length]; 
     file.Read(data, 0, (int)file.Length); 

     Type rt = file.GetType(); 
     List<Type> knownTypes = new List<Type>() { rt.GetType() }; 
     DataContractSerializer deserializer = new DataContractSerializer(typeof(List<Type>), knownTypes); 

     Stream stream = new MemoryStream(); 
     stream.Write(data, 0, data.Length); 
     stream.Position = 0; 
     return deserializer.ReadObject(stream); //exception here 
    } 

Esiste un modo per passare attraverso Questo? O forse c'è un altro modo per memorizzare i tipi?

+3

Si dovrebbe serializzare i ** dati **, non l'implementazione. Un 'Tipo' è al 100% sull'implementazione. Francamente, è semplicemente la strada sbagliata, e sarebbe un disservizio aiutarti ad andare più in là lungo quel sentiero oscuro. IMO. –

+0

Realizzo i dati in serie, ma contiene tipi definiti dall'utente a cui non riesco ad accedere. Quindi quando li deserializzo ho bisogno di sapere che tipi. Pensavo che l'unico modo per accedervi fosse archiviarli in un file. –

risposta

2

Marc Gravell ha ragione, probabilmente dovresti serializzare i dati e non i tipi.

Ma per qualche motivo, se si vuole veramente serializzare i tipi stessi, non si dovrebbe serializzare l'oggetto Type (piuttosto sicuro che non sia sieri). In ogni caso, serializzare Type.FullName invece. Quando si caricano i tipi, utilizzare Type.Load

public static void SaveTypes(IEnumerable<Type> types, string filename) 
{ 
    using (var fs = File.Open(filename, FileMode.OpenOrCreate) 
     new XmlSerializer(typeof(string[])) 
      .Serialize(fs, types.Select(t => t.FullName).ToArray()) 
} 

pubic static IEnumerable<Type> LoadTypes(string filename) 
{ 
    using (var fs = File.Open(filename, FileMode.Open) 
    { 
     var typeNames = (string[]) 
      new XmlSerializer(typeof(string[])) 
      .Deserialize(fs); 

      return typeNames.Select(t => Type.Load(t)); 
    } 
} 

Nota: Quando si lavora con qualsiasi Stream (o realmente qualsiasi IDisposable) bisogna o chiamare il metodo Dispose o utilizzare l'istruzione using (come ho fatto in precedenza). Ciò garantisce che lo IDisposable sia stato correttamente ripulito (cioè rilascia gli handle del File System).

+0

Per qualche motivo non riesco a trovare il metodo Type.Load. Sei sicuro che esista? –

+1

Probabilmente intendeva serializzare ['Type.AssemblyQualifiedName'] (https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname%28v=vs.110%29.aspx) invece di' Type .FullName', per caricare il tipo usando ['Type.GetType'] (https://msdn.microsoft.com/en-us/library/w3f99sx1%28v=vs.110%29.aspx) piuttosto che inesistente' Type.Load', e probabilmente avrebbe suggerito di usare ['IDataContractSurrogate'] (https://msdn.microsoft.com/en-us/library/system.runtime.serialization.idatacontractsurrogate%28v=vs.110%29. aspx) piuttosto che sostituire manualmente i valori prima/dopo la serializzazione. – binki