1

I am trying to work out the best way to serialize nested classes without having to serialize the entire nest class member. Assuming the following the classes:

public class ClassA
{
  public decimal ID { get; set; }
}

public class ClassA1 : ClassA
{
  public decimal Name { get; set; }
  public decimal Value { get; set; }
  public decimal Description { get; set; }
}

public class ClassA2 : ClassA
{
  public ClassA1 Details { get; set; }
  public int SomeValue { get; set; }
}

I have a fixed list of objects of type ClassA1 that are stored in a variable of type List.

I also have a list of objects of type ClassA2 that are stored in a variable of type List

What I would like to do is serialize and deserialize my list of ClassA2 objects. Automatic serialization will serialize the entire contents of each ClassA1 object but I only want to serialize and then deserialize the ClassA1.ID member and then retrieve the object reference from my fixed list upon deserialization.

Automatic Serialization gives me this:

...
<ClassA2>
  <ID>IDStringForObjectClassA2</ID>
  <Details>
    <ClassA1>
      <ID>IDStringForObjectOfClassA1</ID>
      <Name>MyNameValue</Name>
      <Value>MyStringValue</Value>
      <Description>MyDescriptionValue</Description>
    </ClassA1>
  </Details>
  <SomeValue>0</SomeValue>
</ClassA2>

The end result I want in my XML is this

...
<ClassA2>
  <ID>IDStringForObjectClassA2</ID>
  <Details>
    <ClassA1>
      <ID>IDStringForObjectOfClassA1</ID>
    </ClassA1>
  </Details>
  <SomeValue>0</SomeValue>
</ClassA2>

and on deserialization of the ClassA1.ID member, I want to locate a an actual object within a preloaded list

EDIT: Document serializer class below

public class Document
{
  private _ClassA2;

  public Document() { _ClassA2 = null; }

  public ClassA2 ClassA2
  {
    get { return _ClassA2; }
    set { _ClassA2 = value; }
  }

  public string Serialize(StreamWriter writer)
  {
    var serializer = new XmlSerializer(typeof(ClassA2));
    serializer.Serialize(writer, this);
    return writer.ToString();
  }

  public static ClassA2 DeSerialize(StreamReader reader)
  {
    var serializer = new XmlSerializer(typeof(ClassA2 ));
    ClassA2 value = serializer.Deserialize(reader) as ClassA2 ;
    return value;
  }
}
Woodjitsu
  • 231
  • 1
  • 3
  • 8
  • what is the current code you are using for deserialization? – RBT Apr 05 '17 at 07:48
  • Your XML is not valid for deserialization as per the classes your have mentioned. `Details` tag should have a `ClassA1` tag inside it. Also there is no ending tag for `ClassA2`. – RBT Apr 05 '17 at 08:35
  • @RBT I am using the standard XmlSerializer class to Deserialize is there anyway to incorporate the above into this or do I have to change to completely custom deserialization `var serializer = new XmlSerializer(typeof(CableDocument));` `CableDocument value = serializer.Deserialize(reader) as CableDocument;` EDIT: For the life of me I could not get the markdown to work above correctly – Woodjitsu Apr 06 '17 at 08:15
  • Please add your current code into your post. It is better that all the contents of your problem remain in the post rather than in comments. Please put your EDIT into your post instead. Can you please add the definition of `CableDocument` class into your post. – RBT Apr 06 '17 at 08:17
  • @RBT Coded edited – Woodjitsu Apr 07 '17 at 02:37
  • I believe john's solution is what you are looking for then. Simply decorate all three properties namely `Name `, `Value` and `Description` present in `ClassA1` with `[XmlIgnore]` tag. So during serialization only ID field will get serialized. You should be using `System.Xml.Serialization.XmlSerializer` class for all your serialization needs rather writing your own static methods. – RBT Apr 07 '17 at 11:37

2 Answers2

2

To exclude elements, you can either define a "ShouldSerialize" method in the same class as the data:

public bool ShouldSerializeDescription()
{
    return false;
}

public decimal Description { get; set; }

or use the [XmlIgnore] attribute above the property:

[XmlIgnore]
public decimal Description { get; set; }

In most cases I'd recommend XmlIgnore.

Regarding locating a member to populate the field with, there is nothing built in to achieve this as far as I'm aware of. You will just have to loop through and locate the values manually. See this post for more information.

Community
  • 1
  • 1
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
  • John, The reason I havent used XmlIgnore or ShouldSerialize is because the ClassA1 get serialized separately and needs these fields serialized. The issue I have is when serializing classes that contain nested classes. The main class (ClassA2) just needs to serialize and deserialize an ID so that the member variable referencing the nested class can then reference the appropriate ClassA1 object a separately deserialized list of objects. – Woodjitsu Apr 10 '17 at 03:26
  • 1
    The provided link appears to be referencing what I am trying to achieve so I will look at options provided in that thread as well. – Woodjitsu Apr 10 '17 at 03:38
1

I changed the input XMl which is getting serialized a bit to make it a valid XML. Please see the below code which is deserializing only ID property of ClassA1 present in Details property. You will have to use following import using System.Xml.Linq; at the top of your code file.

private static void NestedMemberSerialization()
{

    var serializedXml = "<ClassA2><ID>1</ID><Details><ClassA1><ID>2</ID><Name>4</Name><Value>2</Value><Description>3</Description></ClassA1></Details><SomeValue>2</SomeValue></ClassA2>";

    XDocument doc = XDocument.Parse(serializedXml);

    var mySteps = (from s in doc.Descendants("ClassA2")
                   select new ClassA2
                   {
                       ID = decimal.Parse( s.Element("ID").Value),
                       SomeValue = int.Parse( s.Element("SomeValue").Value),
                       Details = new ClassA1 { ID = decimal.Parse(s.Element("Details").Descendants("ClassA1").Descendants("ID").ElementAt(0).Value) }
                   }).ToList();

}
RBT
  • 24,161
  • 21
  • 159
  • 240