Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find out whether property setter is called in DeSerialization process

Is there a way to find out whether an object property is called as part of the DeSerialization process (e.g. by the XmlSerializationReaderXXX).

Background: A typical scenario is to disable events and complex operations in that case, until the initialization is complete.

One approach I have found, is to "interpret" the stack and look up whether the call is triggered by XmlSerializationReaderXXX, which is not so elegant IMHO. Is there anything better?

public SomeClass SomeProperty
    {
        get { ..... }
        set
        {
            this._somePropertyValue = value;
            this.DoSomeMoreStuff(); // Do not do this during DeSerialization
        }
    }

-- Update --

As Salvatore has mentioned, somehow similar to How do you find out when you've been loaded via XML Serialization?

like image 575
Horst Walter Avatar asked Nov 07 '11 14:11

Horst Walter


2 Answers

I have a possible solution.

public class xxx
{
    private int myValue;

    [XmlElement("MyProperty")]
    public int MyPropertyForSerialization
    {
        get { return this.myValue; }
        set
        {
            Console.WriteLine("DESERIALIZED");
            this.myValue = value;
        }
    }

    [XmlIgnore]
    public int MyProperty
    {
        get { return this.myValue; }
        set
        {
            Console.WriteLine("NORMAL");
            this.myValue = value;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        xxx instance = new xxx();

        instance.MyProperty = 100; // This should print "NORMAL"

        // We serialize

        var serializer = new XmlSerializer(typeof(xxx));

        var memoryStream = new MemoryStream();
        serializer.Serialize(memoryStream, instance);

        // Let's print our XML so we understand what's going on.

        memoryStream.Position = 0;
        var reader = new StreamReader(memoryStream);
        Console.WriteLine(reader.ReadToEnd());

        // Now we deserialize

        memoryStream.Position = 0;
        var deserialized = serializer.Deserialize(memoryStream) as xxx; // This should print DESERIALIZED

        Console.ReadLine();
    }
}

The trick is using the XmlIgnore, it will force the xml serializer to ignore our property, then we use XmlElement to rename the property for serialization with the name of the property we want.

The problem with this technique is that you have to expose a public property for serialization, and is in some way bad because it can virtually be called by everyone. It will not work if the member is private, unfortunally.

It works, is not totally clean, but is thread safe and don't rely on any flag.

Another possibility is to use something like the Memento pattern. Using the same trick you can add a property called for example Memento that returns another object that contains properties suitable only for serialization, it can makes things a little cleaner.

Did you think instead of changing approach and using DataContractSerializer? It is much more powerful and produces pure XML. It supports the OnDeserializationCallback mechanism.

like image 154
Salvatore Previti Avatar answered Oct 06 '22 01:10

Salvatore Previti


Since you got a pretty complex scenario you might want to consider creating a "data core" class which will be actually serialized/deserialized using simple direct way. Then your complex object is constructed from that object and you fire all events/operations as normal. It will make sequence of deserialize -> fire events/operations more explicit and easier to understand.

like image 30
Valentin Kuzub Avatar answered Oct 06 '22 00:10

Valentin Kuzub