11

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?

Community
  • 1
  • 1
Horst Walter
  • 13,663
  • 32
  • 126
  • 228

7 Answers7

5

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.

Salvatore Previti
  • 8,956
  • 31
  • 37
  • Thanks for all your support so far - have to check this one out. Will take me some time. Your generous support is much appreciated! – Horst Walter Nov 07 '11 at 15:30
2

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.

Valentin Kuzub
  • 11,703
  • 7
  • 56
  • 93
1

There's an OnDeserializingAttribute/OnDeserializedAttribute attributes pair. You can set isDeserializing flag while object is being deserialized. I don't know if they play well with XML serialization, though.

Anton Gogolev
  • 113,561
  • 39
  • 200
  • 288
1

For XML Serialization solution could be implementing IXmlSerializable and embedding such logic into the ReadXml()/WriteXml() method

sll
  • 61,540
  • 22
  • 104
  • 156
  • Yes that is a way, but of course he have to implement all the xml <-> properties conversion logic. – Salvatore Previti Nov 07 '11 at 14:56
  • Yep, this is also my impression at the first glance. I do not want to give up all the convenience since I only need a flag. Nevertheless, good to know the IXmlSerializable interface. – Horst Walter Nov 07 '11 at 15:04
1

To have finer control of the deserialization process you could implement IXmlSerializable interface for SomeClass - in ReadXML you can then for example have some field set a flag that you are in deserialization... this flag can then be checked in the respective methods... and on completion it needs to be reset.

Another option (though not for XML IIRC) is to implement the above via OnDeserializingAttribute and OnDeserializedAttribute .

Yahia
  • 69,653
  • 9
  • 115
  • 144
0

I misunderstood the question at first, but you want to ask from within setter if you are called during deserialization. To do that, use a static flag:

    [serializable]
    class SomeClass
    {
       public static IsSerializing = false;
       SomeProperty
       {
            set
            {
                 if(IsSerializing) DoYouStuff();
            }
       }
    }

and then set the flag just before the serialization:

    try
    {
      SomeClass.IsSerializing = true;
      deserializedClass = (SomeClass)serializer.Deserialize(reader);
    }
    finaly
    {
      SomeClass.IsSerializing = false;  //make absolutely sure you set it back to false
    }

Note that same approach can work even if you deserialize a class that contains a member of your class...

zmilojko
  • 2,125
  • 17
  • 27
  • @SalvatorePreviti: Please explain why not? – zmilojko Nov 07 '11 at 14:57
  • 1
    Because you can have multiple instances of the same class, at that point, one can be during serialization and another one not. In a multithreaded environment it will be unpredictable behaviour. – Salvatore Previti Nov 07 '11 at 14:57
  • Static won't work, as I have to decide per instance. Thanks anyway. – Horst Walter Nov 07 '11 at 14:57
  • The principle can work if you remove the "static" and keep the field private and non serialized of course. – Salvatore Previti Nov 07 '11 at 14:58
  • @SalvatorePreviti That is correct, in multithreaded or otherwise complicated environment (you are changing one object while deserializing another) this wouldn't work... Seems to me that if that is the case a redesign might help. – zmilojko Nov 07 '11 at 15:01
0

Set a breakpoint on the property, and run in debug mode. It will break at the point of access for the getter/setter that you set the breakpoint on.

Charles Lambert
  • 5,042
  • 26
  • 47