2012-04-02 4 views
10

Ho una classe che deve essere serializzata e deserializzata.Sovrascrittura della deserializzazione XML per utilizzare la deserializzazione di base e l'aggiunta di funzionalità

Ma ogni volta dopo la deserilazione ho bisogno di chiamare un metodo per sincronizzare i riferimenti.

In ogni caso, posso implementare la deserializzazione e utilizzare la deserializzazione tradizionale ma aggiungere la chiamata al metodo dopo la deserializzazione normale?

+0

Può chiarire che cosa esattamente si intende per "I neeed per chiamare un mthod di sincronizzare i riferimenti"? Per favore, spiega _why_ anche questo è necessario. – Oded

+0

per esempio la classe include: membro A, membroB e un elenco di membri che ha xmlIgnore e dovrebbe contian il membro A e B la desrializzazione regolare creerà diverse istanze per la lista e il membro ho bisogno della lista per fare riferimento ai membri che sono stati deserizzati . la domanda su come creare un metodo di post-desrializzazione? o implementare e chiamare la deserializzazione normale – user271077

+0

Puoi fornire un esempio? Non è ancora chiaro cosa stai cercando di realizzare. Stai cercando di popolare altri campi membri con 'XmlIgnore' su un oggetto dopo ogni deserializzazione? – mellamokb

risposta

8
using System.Xml.Serialization; 

namespace Custom.Xml.Serialization 
{ 
    public interface IXmlDeserializationCallback 
    { 
     void OnXmlDeserialization(object sender); 
    } 

    public class CustomXmlSerializer : XmlSerializer 
    { 
     protected override object Deserialize(XmlSerializationReader reader) 
     { 
      var result = base.Deserialize(reader); 

      var deserializedCallback = result as IXmlDeserializationCallback; 
      if (deserializedCallback != null) 
      { 
       deserializedCallback.OnXmlDeserialization(this); 
      } 

      return result; 
     } 
    } 
} 

ereditano la classe da IXmlDeserializationCallback e implementare la logica di sincronizzazione nella OnXmlDeserialization metodo.

crediti a How do you find out when you've been loaded via XML Serialization?

UPDATE:

bene, per quanto ho capito il topicstarter, lui non vuole "manualmente" chiamare una logica dopo ogni deserializzazione XML. Quindi, invece di fare questo:

public class MyEntity 
{ 
    public string SomeData { get; set; } 

    public void FixReferences() 
    { 
      // call after deserialization 
      // ... 
    } 
} 

foreach (var xmlData in xmlArray) 
{ 
    var xmlSer = new XmlSerializer(typeof(MyEntity)); 
    using (var memStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlData))) 
    { 
     var entity = (MyEntity)xmlSer.Deserialize(memStream); 
     entity.FixReferences(); 

     // do something else with the entity 
     // ... 
    } 
} 

lui vuole fare solo la deserializzazione, senza preoccuparsi di chiamate extra. In questo caso, la soluzione proposta è il più pulito/più semplice - è sufficiente per ereditare la classe entità dall'interfaccia IXmlDeserializationCallback, e sostituirlo con XmlSerializer CustomXmlSerializer:

public class MyEntity: IXmlDeserializationCallback 
    { 
     public string SomeData { get; set; } 

     private void FixReferences() 
     { 
       // call after deserialization 
       // ... 
     } 

     public void OnXmlDeserialization(object sender) 
     { 
      FixReferences(); 
     } 
    } 

    foreach (var xmlData in xmlArray) 
    { 
     var xmlSer = new CustomXmlSerializer(typeof(MyEntity)); 
     using (var memStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlData))) 
     { 
      var entity = (MyEntity)xmlSer.Deserialize(memStream); 
      // entity.FixReferences(); - will be called automatically 

      // do something else with the entity 
      // ... 
     } 
    } 
+1

Purtroppo, il metodo sottoposto a override non viene mai chiamato ... – Herdo

+0

Qualche idea sul perché i metodi sottoposti a override non vengano chiamati in .NET 4.5? – Raj

4

Le opzioni che utilizzano XmlSerializer sono limitate.

  • Deserializza l'intero grafico dell'oggetto e quindi applica le correzioni necessarie.
  • Effettua qualche elaborazione nei setter della proprietà del tuo oggetto.
  • Implementare IXmlSerializable sui tipi in modo da avere il controllo esplicito della serializzazione/deserializzazione. Non è un'opzione facile.

Se è possibile modificare a utilizzare il DataContractSerializer, che ha le sue advantanges (e svantaggi), allora si può usare il OnDeserializedAttribute. Per esempio

[DataContract] 
public class MyClass 
{ 
    [DataMember] 
    public string AMember{get;set;} 

    [OnDeserialized] 
    public void OnDeserialized(StreamingContext context) 
    { 
     // called after deserializing instance of MyClass 
    } 
} 
1

ho una bella soluzione 4 u

scrittura questa classe statica

public delegate void OnDeserializedEventArgs(object itemDeserialized, string xmlSource); 
public delegate void OnDeserializedFailedEventArgs(string xmlSource); 
public static class SerializationServices 
{ 
    public static event OnDeserializedEventArgs OnDeserializedEvent; 
    public static event OnDeserializedFailedEventArgs OnDeserializedFailedEvent; 

    public static T Deserialize<T>(this string item) where T : class 
    { 
     XmlSerializer ser = new XmlSerializer(item.GetType()); 
     StringReader sr = new StringReader(item); 
     var obj = ser.Deserialize(sr); 

     if (obj is T) 
     { 
      if (OnDeserializedEvent != null) 
       OnDeserializedEvent(obj, item); 

      return obj as T; 
     } 

     if (OnDeserializedFailedEvent != null) 
      OnDeserializedFailedEvent(item); 

     //callback - invalid event 
     return null; 
    } 
} 

e quindi utilizzarlo con questo codice

public class MyDesrializedClass 
{ 
    //put some properties here... 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     SerializationServices.OnDeserializedEvent += SerializationServices_OnDeserializedEvent; 
     SerializationServices.OnDeserializedFailedEvent += SerializationServices_OnDeserializedFailedEvent; 

     string someXml = string.Empty; //replace this with something... 
     MyDesrializedClass deserializedClass = someXml.Deserialize<MyDesrializedClass>(); 
    } 

    private static void SerializationServices_OnDeserializedFailedEvent(string xmlSource) 
    { 
     //will get here before 'deserializedClass' will get it's results 
    } 

    private static void SerializationServices_OnDeserializedEvent(object itemDeserialized, string xmlSource) 
    { 
     //will get here before 'deserializedClass' will get it's results 
    } 
} 

se u incollare questi codice in diversi spazi dei nomi non dimenticare di aggiungere l'opzione 'using ...' otherwize u non vedrai il metodo deserialize nel contex del programma t

Tzahi

+0

avviso che la mia soluzione non richiede che tu erediti qualsiasi classe base e non richiede che tu inizializzi nuove istanze – Tzahi