W.Harr
W.Harr

Reputation: 303

How to use ShouldSerialize[MemberName]() to Conditionally Serialize Element Within Property of Object Where Property is a List?

I have a class "Hospitalization" which I need to Serialize as an XML string. That class has a property "ActiveDiagnoses" which is a list of type "DiagnosisCode".

In that collection, only the elements with the property Order with a value of less than three should be included in the serialized string.

Here is an example (which fails to only serialize the DiagnosisCodes with an order less than 3):

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

namespace XmlConditionalSerializationOnListExample
{
    [XmlRoot]
    public class Hospitalization
    {
        public string PatientName { get; set; }
        public DateTime AdmitDate { get; set; }

        [XmlElement("DiagnosisCode")]
        public List<DiagnosisCode> ActiveDiagnoses { get; set; }
    }

    public class DiagnosisCode
    {
        public string Code { get; set; }
        public string CodeSet { get; set; }

        [XmlIgnore]
        public int Order { get; set; }

    }

    class Program
    {

        static void Main(string[] args)
        {
            Hospitalization hospitalization = new Hospitalization() { PatientName = "Test Patient", AdmitDate = DateTime.Now.Date };

            List<DiagnosisCode> Dxs = new List<DiagnosisCode>()
            {
                new DiagnosisCode(){Code="Z99.81", CodeSet="ICD10", Order = 1}
                ,new DiagnosisCode(){Code="Z99.0", CodeSet="ICD10", Order = 2}
                ,new DiagnosisCode(){Code="Z98.5", CodeSet="ICD10", Order = 3}
            };

            hospitalization.ActiveDiagnoses = Dxs;

            string HospitalizationXml = String.Empty;
            XmlSerializer Ser = new XmlSerializer(hospitalization.GetType());
            //XmlSerializer Ser = new XmlSerializer(Hospitalization);

            using (StringWriter writer = new StringWriter())
            {
                Ser.Serialize(writer, hospitalization);
                HospitalizationXml = writer.ToString();
            }

            Console.WriteLine("Hospitalization object as represented by XML string:\n{0}", HospitalizationXml);

            Console.ReadKey();
        }
    }

}

My first thought was to set change the line where I assign the Dxs variable as the value for the ActiveDiagnoses property with a foreach loop which would conditionally add an XmlIgnore attribute to each DiagnosisCode with an order property value above 2 but apparently you aren't able to do that dynamically.

I then found a couple of examples of people using ShouldSerialize() Methods to determine whether or not a property would be serialized:

Example 1 Example 2

The difference between my scenario and the ones linked above is that Example 1 adds a ShouldSerialize() method for a property which isn't a List and although the second does add the ShouldSerialize() method for a List property, that method determines weather or not the entire list of elements is serialized, not particular elements within it.

I attempted to add the following method to the DiagnosisCode class:

public bool ShouldSerializeDiagnosisCode()
{
     return Order < 3 ? true : false;
}

However it had no effect. I tried to move that method to the Hospitalization class but got a compile error as would be expected because the compiler doesn't know what I'm referring to with the Order property.

I did end up with a workaround by doing the following:

1: Change the Hospitalization class to have two lists of DiagnosisCode objects, where one of them is marked as to be ignored when serializing as XML.

[XmlRoot]
public class Hospitalization
{
    public string PatientName { get; set; }
    public DateTime AdmitDate { get; set; }

    [XmlElement("DiagnosisCode")]
    public List<DiagnosisCode> ActiveDiagnoses { get; set; }

    [XmlIgnore]
    public List<DiagnosisCode> NonBillableDiagnoses { get; set; }
}

2: Change my Main() method to add each diagnosis in a loop and determine which of the two Lists to add the DiagnosisCode to based on its OrderIndex at that point in time.

//hospitalization.ActiveDiagnoses = Dxs;

hospitalization.ActiveDiagnoses = new List<DiagnosisCode>();
hospitalization.NonBillableDiagnoses = new List<DiagnosisCode>();

foreach (DiagnosisCode dx in Dxs)
{
    if (dx.Order < 3)
    {
        hospitalization.ActiveDiagnoses.Add(dx);
    }
    else
    {
        hospitalization.NonBillableDiagnoses.Add(dx);
    }
}

That solution works ok but I'd like to know if there's a way where I could use the ShouldSerialize method in the way I intended as described above.

Any help/ suggestions you can provide I'd greatly appreciate.

Upvotes: 0

Views: 841

Answers (1)

ferc
ferc

Reputation: 558

That's just not the intended purpose of the ShouldSerialize pattern. If you need to transform your data before serialization, just do it in code, as you're doing it already.

If you want to keep it in your Hospitalization class, you can filter the list there in the property's getter, like so:

[XmlRoot]
public class Hospitalization
{
    public string PatientName { get; set; }
    public DateTime AdmitDate { get; set; }

    [XmlIgnore]
    public List<DiagnosisCode> ActiveDiagnoses { get; set; }

    [XmlElement("DiagnosisCode")]
    public List<DiagnosisCode> SerializableDiagnoses { get { return ActiveDiagnoses.Where(d => d.Order <= 2).ToList(); } }
}

Upvotes: 2

Related Questions