none
How does this XmlSerialize code deserialize the collection? RRS feed

  • Question

  • I've come across a situation with XmlSerializer that I don't understand.

    In the following code example I have a List<string> that is serialized/deserialized and the end result is correct.

    However, when debugging (and visible from the tracing to the console output), the property setter for MyItems is assigned an empty collection when deserialized - but after Deserialize, the property and backing store have 3 items in them.

    How does this work, presumably there's something going on behind the scenes that I'm not aware of?

    I'm asking because I'm trying to do something a little more involved in a real application, and I need the property setter to have the expected collection, but it's behaving like this simple example and confounding me. :(

        public class MyData
        {
            public MyData()
            {
            }
            [XmlArray]
            public List<string> MyItems
            {
                get { return BackingStoreItems; }
                set
                {
                    Console.WriteLine( "Item setter: {0}", value.Count() );
                    BackingStoreItems = value;
                }
            }
            private List<string> BackingStoreItems;
        }
    
        class Program
    	{
            static void Main( string[] args )
    		{
                MyData d1 = new MyData();
                d1.MyItems = new List<string> { Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), "Close to the Edge" };
                XmlSerializer ser = new XmlSerializer( typeof( MyData ) );
                StreamWriter wr = new StreamWriter( "MyDataFile.xml" );
                ser.Serialize( wr, d1 );
                wr.Close();
                Console.WriteLine( "Serialization finished. There are {0} items", d1.MyItems.Count() );
    
                FileStream fs = new FileStream("MyDataFile.xml", FileMode.Open );
                MyData d2 = (MyData) ser.Deserialize( fs );
                fs.Close();
                Console.WriteLine( "De-serialization finished. There are {0} items", d2.MyItems.Count() );
            }
    

    Monday, December 18, 2017 5:11 PM

Answers

  • Probably the system creates a new list using ‘new List<string>’, which is initially empty, then assign it to the property, then continue the deserialization, adding read items to the list.

    In order to be notified, or just to check this, try an observable list:

    [XmlArray]
    public ObservableCollection<string> MyItems
    {
       get { return BackingStoreItems; }
       set
       {
          Console.WriteLine( "Item setter: {0}", value.Count() );
          if( BackingStoreItems != null ) BackingStoreItems.CollectionChanged -= MyHandler;
          BackingStoreItems = value;
          if( BackingStoreItems != null ) BackingStoreItems.CollectionChanged += MyHandler;
       }
    }
    
    void MyHandler( object sender, NotifyCollectionChangedEventArgs args )
    {
       Console.WriteLine( "Collection changed: {0}", BackingStoreItems.Count() );
    }
    

    Monday, December 18, 2017 8:32 PM

All replies

  • Probably the system creates a new list using ‘new List<string>’, which is initially empty, then assign it to the property, then continue the deserialization, adding read items to the list.

    In order to be notified, or just to check this, try an observable list:

    [XmlArray]
    public ObservableCollection<string> MyItems
    {
       get { return BackingStoreItems; }
       set
       {
          Console.WriteLine( "Item setter: {0}", value.Count() );
          if( BackingStoreItems != null ) BackingStoreItems.CollectionChanged -= MyHandler;
          BackingStoreItems = value;
          if( BackingStoreItems != null ) BackingStoreItems.CollectionChanged += MyHandler;
       }
    }
    
    void MyHandler( object sender, NotifyCollectionChangedEventArgs args )
    {
       Console.WriteLine( "Collection changed: {0}", BackingStoreItems.Count() );
    }
    

    Monday, December 18, 2017 8:32 PM
  • Thanks for that, the console tracing for deserialization now shows:

    Item setter: 0
    Collection changed: 1
    Collection changed: 2
    Collection changed: 3
    De-serialization finished. There are 3 items

    ...which may give me something to consider for solving my real problem (I'll give that a try tomorrow), but I'm still mighty confused over why the property setter is called but effectively useless. In similar situations (without collections), the property setter works as I'd expect.

    Monday, December 18, 2017 10:07 PM
  • Having now found this information I can now debug into the generated deserialization code and see that indeed the generated code does do as you say...

    It creates a new empty collection, assigns it to the member, then adds the elements to it.

    If only it'd do it on a local variable, then add the elements to that, and then assign that to the member, the issue wouldn't exist :)

    I'm still not sure how to resolve my real problem, but thanks for enlightening me.

    Tuesday, December 19, 2017 11:13 AM