none
How to serialize/deserialize class-wrapper of IList collection? RRS feed

  • Question

  • I have base class Control, which contains a property public ControlCollection Controls:

    public abstract class Control { ... public virtual string Name { get: set; } public ControlCollection Controls;

    public Control parent = null; ... }



    ControlCollection is my own class, which implements IList<Control>:
    public sealed class ControlCollection : IList<Control>, IMySerializable {       
        public int Count => _controls.Count;
        public bool IsReadOnly { get; } = false;
        public Control Parent;
    
        private List<Control> _controls = new List<Control>();
    
        public ControlCollection(Control parent) {
            Parent = parent ?? throw new ArgumentNullException("parent");
        }
    
        public Control this[int index] {
            get => _controls[index];
            set => _controls[index] = value;
        }
    
        public void Add(Control child) {
            child.parent = Parent;
            _controls.Add(child);
        }
    
        ...
    }


    If I change a type of property Controls from ControlCollection to List<Control>, then code below will form a correct XML file
    // temp data
    Control rootObj = new Button();  rootObj.Name = "111";
    Control obj2 = new Label();   obj2.Name = "222";
    Control obj3 = new Button();  obj3.Name = "333";    
    rootObj.Controls.Add(obj2); 
    rootObj.Controls.Add(obj3);
    
    List<Type> list = new List<Type>();
    rootObj.Controls.ForEach(child => child.DoActionWithChildren(node => {
        list.Add(node.GetType());
    }));
    
    list.Add(typeof(Button));
    list = list.Distinct().ToList();
    
    // trying to set xml attributes. 'Controls' property will be a root of collection
    var attributes = new XmlAttributes();
    list.ForEach(t => attributes.XmlArrayItems.Add(new XmlArrayItemAttribute(t)));
    var attrOverride = new XmlAttributeOverrides();
    attrOverride.Add(typeof(Control), "Controls", attributes); 
    
    // save data to file    
    using(StreamWriter sw = new StreamWriter("path/to/xml/file.xml", false, Encoding.UTF8)) {
        XmlSerializer xs = new XmlSerializer(typeof(Control), attrOverride);        
        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add(string.Empty, string.Empty);
        xs.Serialize(sw, rootObj, ns);  
    }
    
    /* ---------------------- */
    output:
    
    <?xml version="1.0" encoding="utf-8"?>
    <Control d1p1:type="Button" xmlns:d1p1="http://www.w3.org/2001/XMLSchema-instance">
      <Controls>
        <Control d1p1:type="Label">
          <Controls />      
          <Name>22222</Name>
        </Control>
        <Control d1p1:type="Button">
          <Controls />
          <Name>32333</Name>      
        </Control>
      </Controls>  
      <Name>1111</Name>  
    </Control>


    But if a type of property Controls is ControlCollection, then XML will be cut off:
    <?xml version="1.0" encoding="utf-8"?>
    <Button>
      <Controls>
        <Control d3p1:type="Label" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance">
          <Controls />

    I tried to change the type: attrOverride.Add(<g class="gr_ gr_18 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling" data-gr-id="18" id="18">typeof</g>(ControlCollection), "Controls", attributes), but this doesn't work.

    What should I do to serialize ControlCollection properly? And what should I know to properly deserialize it afterward?


    • Edited by i-programmer Thursday, June 28, 2018 6:59 AM incorrect html in question
    Wednesday, June 27, 2018 10:24 AM

Answers

  • Well, I fixed it. It turned out that I had a circular reference because of a property in my base class:

    public Control parent = null;

    I wrote an attribute  [XmlIgnore] and it worked, even with this:

    attrOverride.Add(typeof(ControlCollection), "Controls", attributes);

    The reason why I didn't see this error is that my original project is a Unity project. And *Unity* didn't show me that error. When I made a simple C# Console application - it showed me that error. It's sad but true.


    • Edited by i-programmer Thursday, June 28, 2018 7:04 AM
    • Proposed as answer by Dolen Zhang Thursday, June 28, 2018 7:47 AM
    • Marked as answer by i-programmer Thursday, June 28, 2018 11:36 AM
    Thursday, June 28, 2018 7:01 AM

All replies

  • What should I do to serialize ControlCollection properly? And what should I know to properly deserialize it afterward?

    Use a List<T> of custom types

    Wednesday, June 27, 2018 3:57 PM
  • Well, I fixed it. It turned out that I had a circular reference because of a property in my base class:

    public Control parent = null;

    I wrote an attribute  [XmlIgnore] and it worked, even with this:

    attrOverride.Add(typeof(ControlCollection), "Controls", attributes);

    The reason why I didn't see this error is that my original project is a Unity project. And *Unity* didn't show me that error. When I made a simple C# Console application - it showed me that error. It's sad but true.


    • Edited by i-programmer Thursday, June 28, 2018 7:04 AM
    • Proposed as answer by Dolen Zhang Thursday, June 28, 2018 7:47 AM
    • Marked as answer by i-programmer Thursday, June 28, 2018 11:36 AM
    Thursday, June 28, 2018 7:01 AM