2012-04-02 12 views
10

Mam klasę, która powinna zostać przekształcona do postaci szeregowej i ponownie sformatowana.Nadpisywanie deserializacji XML w celu korzystania z deserializacji podstawowej i dodawania funkcjonalności

Ale za każdym razem po dewastyzacji muszę wywołać metodę synchronizowania odniesień.

W każdym razie mogę przeprowadzić deserializację i użyć tradycyjnej deserializacji, ale dodać wywołanie do mojej metody po regularnej deserializacji?

+0

Czy możesz wyjaśnić, co dokładnie masz na myśli przez "Czy mogę nazwać podłoże synchronizacji odniesień"? Proszę wyjaśnić, dlaczego tak jest również potrzebne. – Oded

+0

na przykład klasa zawiera: element A, element członkowski i listę członków, która ma xmlIgnore i powinna contian członek A i B regularne desrializacje będą tworzyć różne instancje dla listy i członek, którego potrzebuję na liście, aby odwołać się do członków, które zostały zhakłowane . pytanie, jak stworzyć metodę deskrypcji postów? lub zaimplementować i wywołać regularną deserializację – user271077

+0

Czy możesz podać przykład? Wciąż nie jest jasne, co próbujesz osiągnąć. Chcesz wymieniać inne pola elementu z 'XmlIgnore' na obiekcie po każdej deserializacji? – mellamokb

Odpowiedz

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; 
     } 
    } 
} 

dziedziczy swoją klasę od IXmlDeserializationCallback i implementuje logikę synchronizacji w metodzie OnXmlDeserialization.

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

UPDATE:

dobrze, o ile mi zrozumieć topicstarter, on nie chce się "ręcznie" nazywamy jakąś logikę po każdym deserializacji XML. Zamiast tego:

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 
     // ... 
    } 
} 

chce zrobić tylko deserializację, nie martwiąc się o dodatkowe połączenia. W tym przypadku, proponowane rozwiązanie jest najczystszym/najprostszy - trzeba tylko dziedziczą swoją klasę podmiot z interfejsem IXmlDeserializationCallback i zastąpić XmlSerializer z 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

Niestety, metoda nadpisywana nigdy nie jest wywoływana ... – Herdo

+0

Każdy pomysł, dlaczego nadpisane metody nie są wywoływane w .NET 4.5? – Raj

4

Twoje opcje wykorzystujące XmlSerializer są ograniczone.

  • Oddestrykuj cały wykres obiektu, a następnie zastosuj dowolne wymagane poprawki.
  • Wykonaj pewne przetwarzanie w ustawieniach właściwości obiektu.
  • Wykonaj IXmlSerializable na swoich typach, aby mieć wyraźną kontrolę nad serializacją/deserializacją. Nie jest to łatwa opcja.

Jeśli można zmienić za pomocą DataContractSerializer, który ma swoje wady i advantanges(), a następnie można użyć OnDeserializedAttribute. Na przykład

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

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

Mam ładne rozwiązanie 4 u

napisać to statyczna klasa

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; 
    } 
} 

a następnie używać go z tym kodem

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 
    } 
} 

jeśli u wklej te kod do różnych przestrzeni nazw nie zapomnij dodać "używając ...", inaczej nie zobaczymy metody deserializacji w programie contex t

Tzahi

+0

Zauważ, że moje rozwiązanie nie wymaga dziedziczenia żadnej klasy bazowej i nie wymaga zainicjowania nowych instancji – Tzahi

Powiązane problemy