10

I have a class which should be serialized and deserialzed.

But every time after deserilization I need to call a method of synchronizing references.

Anyway I can implement the deserialization and use the traditional deserialization but add the call to my method after the regular deserialization?

LarsTech
  • 80,625
  • 14
  • 153
  • 225
user271077
  • 996
  • 1
  • 19
  • 35
  • Can you clarify what exactly you mean by "I Neeed to call a mthod of synchronizing references"? Please explain _why_ this is needed as well. – Oded Apr 02 '12 at 08:50
  • for example class includes: member A, MemberB, and a list of members which has xmlIgnore and should contian the member A and B regular desrialization will create different instances for the list and the member I need the list to reference the members which were deserilized. the question how to create a post desrialization method? or implement and call teh regular deserialization – user271077 Apr 02 '12 at 08:54
  • Can you provide an example? It's still unclear what you are trying to accomplish. You are wanting to populate other member fields with `XmlIgnore` on an object after every deserialization? – mellamokb Apr 04 '12 at 13:20

3 Answers3

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

inherit your class from IXmlDeserializationCallback and implement your synchronizing logic in OnXmlDeserialization method.

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

UPDATE:

well, as far as I understand the topicstarter, he does not want to "manually" call some logic after each XML deserialization. So instead of doing this:

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

he wants to do just deserialization, without worrying about extra calls. In this case, proposed solution is the cleanest / simplest - you only need to inherit your entity class from IXmlDeserializationCallback interface, and replace XmlSerializer with 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
           // ...  
        }
    }
Community
  • 1
  • 1
avs099
  • 10,937
  • 6
  • 60
  • 110
4

Your options using XmlSerializer are limited.

  • Deserialize your entire object graph and then apply whatever fix-ups you require.
  • Do some processing in the property setters of your object.
  • Implement IXmlSerializable on your types so that you have explicit control of serialization/deserialization. Not an easy option.

If you can change to using the DataContractSerializer, which has its advantanges (and disadvantages) then you can use the OnDeserializedAttribute. For example

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

    [OnDeserialized]
    public void OnDeserialized(StreamingContext context)
    {
        // called after deserializing instance of MyClass
    }
}
Phil
  • 42,255
  • 9
  • 100
  • 100
1

i have a nice solution 4 u

write this static class

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

and then use it with this code

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

if u paste these code into diferent namespaces don't forget to add the 'using ...' otherwize u wont see the method deserialize in the program context

Tzahi

Tzahi
  • 129
  • 1
  • 8
  • notice that my solution does not require u to inherit any base class and it doesn't require u to initialize new instances – Tzahi Apr 10 '12 at 10:53