0

So, I have recently had occasion to use a technique which, for lack of a better term, I have dubbed a "Matroyshka Class", after the Russian nested dolls. The class has a List property that contains instances of the same class, each of which also has a similar list, to a more-or-less arbitrary "depth".

Here is a simplified example of what that might look like:

class Doll
{
    public string Color;
    public List<Doll> ChildDolls;
    // End of properties. Getters and Setters not included for readability.

    public Doll(string color)
    {
        this.Color = color;
        this.ChildDolls = new List<Doll>();
    } // End of Constructor

    public void AddChild(Doll NewChild)
    {
        this.ChildDolls.Add(NewChild);
    } // End of Add Child method

    public override string ToString()
    {
        string output;

        // Adds the current doll's color
        output += this.Color + "\n";

        // Adds each doll's children, and each of theirs, and so on...
        foreach (Doll Child in this.ChildDolls)
        {
            output += Child.ToString();
        }
        return output;
    } // End of To String method

} // End of class

Anyways. I have run into a bit of a wall. I need the ability to read and write them to an XML file (Or some similar external file, I suppose) because my program will ultimately involve a lot of these; putting them in the code itself seems ill advised. Writing should be relatively straightforward, using a technique similar to the example's ToString() method. However, I'm lacking in ideas for reading them after the fact, because of the arbitrary "depth".

  • Can you please clarify what exact problems you have when [serialize to XML](https://stackoverflow.com/questions/4123590/serialize-an-object-to-xml) or some other format like [ json](https://stackoverflow.com/questions/7895105/deserialize-json-with-c-sharp) ? Not exactly clear why "arbitrary depth" is a problem for serialization... – Alexei Levenkov Mar 20 '20 at 01:45
  • Because I didn't know what serialization was -w- XML is still a relatively new tool to me... – Seth Veeper Mar 20 '20 at 11:07

1 Answers1

0

There is everything you need in the System.Xml.Serialization namespace. Here is an example of how your Matryoshka class may look like (only a few small changes needed):

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml.Serialization;

public class Doll  //must be public
{
    public string Color { get; set; }
    public List<Doll> ChildDolls { get; set; } = new List<Doll>();

    public Doll() //needs a ctor without parameters
    {
        Color = "Not set";
    }

    public Doll(string color)
    {
        this.Color = color;
    } // End of Constructor

    public void AddChild(Doll NewChild)
    {
        this.ChildDolls.Add(NewChild);
    } // End of Add Child method

    public override string ToString()
    {
        var output = new StringBuilder();

        // Adds the current doll's color
        output.AppendLine(Color);

        // Adds each doll's children, and each of theirs, and so on...
        foreach (Doll Child in this.ChildDolls)
        {
            output.Append(Child.ToString());
        }
        return output.ToString();
    } // End of To String method

} // End of class

And here are the serialization/deserialization methods:

    public static void Serialize(string path, Doll matryoshka)
    {
        using (var writer = new StreamWriter(path))
        {
            var s = new XmlSerializer(typeof(Doll));
            s.Serialize(writer, matryoshka);
        }
    }

    public static Doll Deserialize(string path)
    {
        using (var reader = new StreamReader(path))
        {
            var x = new XmlSerializer(typeof(Doll));
            return (Doll)x.Deserialize(reader);
        }
    }

Using them is pretty straightforward:

        var redDoll = new Doll("red");

        var green1Doll = new Doll("green1");
        var green2Doll = new Doll("green2");

        var blue1Doll = new Doll("blue1");
        var blue2Doll = new Doll("blue2");

        redDoll.AddChild(green1Doll);
        redDoll.AddChild(green2Doll);

        green1Doll.AddChild(blue1Doll);

        green2Doll.AddChild(blue2Doll);

        Serialize("dolls.xml", redDoll);

The result will be like this:

<?xml version="1.0" encoding="utf-8"?>
<Doll xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Color>red</Color>
  <ChildDolls>
    <Doll>
      <Color>green1</Color>
      <ChildDolls>
        <Doll>
          <Color>blue1</Color>
          <ChildDolls />
        </Doll>
      </ChildDolls>
    </Doll>
    <Doll>
      <Color>green2</Color>
      <ChildDolls>
        <Doll>
          <Color>blue2</Color>
          <ChildDolls />
        </Doll>
      </ChildDolls>
    </Doll>
  </ChildDolls>
</Doll>

Deserialization works fine too:

        var deserializedDoll = Deserialize("dolls.xml");
        Console.Write(deserializedDoll.ToString());

The output, as expected, is:

red
green1
blue1
green2
blue2

You can also control how your XML is generated by the serializer using attributes. Here are the docs

Pavel Zhuravlev
  • 2,691
  • 1
  • 18
  • 17