0

Okay so I want to try to make a generic implementation to save settings of what could be many different types of generic objects. So say I have a class that is serializable of Person:

using System;       
using System.Xml;           
using System.Xml.Serialization;

[Serializable]
public class Person
{       
  [XmlAttribute]
  public string PersonName { get; set; }

  public Person(string name)
  {
    PersonName = name;
  }

  public Person()  {}                   
}

And it serializes just fine like this:

<Person PersonName="Brett" />

But say I want to reproduce a pattern for saving many of these and also different structures that may be something like this:

<Order OrderId="1">
   <SKU>Pants</SKU>
</Order>

I can also do that and it works fine. The problem is that I want to setup a container method so that I can assign a Name to the complex object and then have N numbers of them in a collection. I make up a generic class like so to do this:

using System;
using System.Runtime.Serialization;
using System.Xml.Serialization;

[Serializable]
public class SerializeContainer<T> where T : class, new()
{                 
  [XmlAttribute]
  public string Name { get; set; }
  public T Setting { get; set; }                                                                                          
  public SerializeContainer() { }

  public SerializeContainer(string name, T setting)
  {
    if (!typeof(T).IsSerializable && ! typeof(ISerializable).IsAssignableFrom(typeof(T)))) 
    {
      throw new InvalidOperationException("A Serializable Type is required.  Please ensure that the class used has the proper Serializable Attribute set.");
    }

    Name = name;
    Setting = setting;
  }
}

This serializes but the Node overrides my child node(T)'s root name with it's own like so:

<SerializeContainerOfPerson Name=\"Test\">
   <Setting PersonName=\"Brett\" />          
</SerializeContainerOfPerson>

But what I really want is to keep my original structure and just wrap around it like so:

<SerializeContainerOfPerson Name=\"Test\">
   <Person PersonName=\"Brett\" />          
</SerializeContainerOfPerson>

I have been trying to trick it with [XMLElementName(nameof(T))]. But of course that just renames the node to

 <T ...

, so not really an answer. And due to the nature of the XML attribute adornments they have set rules so doing anything to find out the generic that I have tried doesn't work. Is there a way to do it or at least maybe I should go an interface route or another patter to basically do something that is reusable to keep the structure and just give it a name and serialize them both with keeping the structure intact.

djangojazz
  • 14,131
  • 10
  • 56
  • 94
  • Is this a duplicate? [Rename class when serializing to XML](https://stackoverflow.com/a/36804496/3744182) – dbc Mar 24 '17 at 02:44
  • Actually it is not, that is a great example but there are two things different in that post: 1. They are NOT using a generic and I am for reuse patterns. 2. When I attempt to substitute in this: '[XMLElement(typeof(T))]' or different patterns to get the type of T it does not work for the adornment. So basically, yes that answer is very close. No it's not the same unfortunately. – djangojazz Mar 24 '17 at 15:48

1 Answers1

0

So in essence what I was seeking appeared to be satisfied by creating my own serializable dictionary. Essentially I only wanted key pairs of N times with a name(key) and 3d xml structure(value). I found this online: http://huseyint.com/2007/12/xml-serializable-generic-dictionary-tipi/

Where essentially you inherit from a dictionary and keep the generics but implement IXMLSerializable and then it get's the types when it does it's write and read methods it must implement. Good stuff and very flexible, which is what I wanted:

[XmlRoot("setting")]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
    #region IXmlSerializable Members
    public System.Xml.Schema.XmlSchema GetSchema()
    {
      return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
      XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
      XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

      bool wasEmpty = reader.IsEmptyElement;
      reader.Read();

      if (wasEmpty)
        return;

      while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
      {
        //reader.ReadStartElement("item");

        reader.ReadStartElement("key");
        TKey key = (TKey)keySerializer.Deserialize(reader);
        reader.ReadEndElement();

        reader.ReadStartElement("value");
        TValue value = (TValue)valueSerializer.Deserialize(reader);
        reader.ReadEndElement();

        this.Add(key, value);

        //reader.ReadEndElement();
        reader.MoveToContent();
      }
      reader.ReadEndElement();
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
      XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
      XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));

      foreach (TKey key in this.Keys)
      {
        //writer.WriteStartElement("item");

        writer.WriteStartElement("key");
        keySerializer.Serialize(writer, key);
        writer.WriteEndElement();

        writer.WriteStartElement("value");
        TValue value = this[key];
        valueSerializer.Serialize(writer, value);
        writer.WriteEndElement();

        //writer.WriteEndElement();
      }
    }
}
djangojazz
  • 14,131
  • 10
  • 56
  • 94