C# Xml Deserialize plus design suggestions

2019-07-23 16:15发布

问题:

In my project I need to build a generic deserializer that should be backward compatible. Example: The XML looks like

<PolicyDef name = "sample" type="type1">
  <Options ......>
</PolicyDef>

The "type" is enum - PolicyTypes e.g

public Enum PolicyTypes
{
 type1 = 0,
 type2 = 1
}

The PolicyDef class is defined as

[XmlRoot("PolicyDef")]
    public class PolicyDef
    {
        private string policyName;
        private PolicyTypes policyType;

        public PolicyDefinition()
        {         
        }

        [XmlAttribute]
        public string Name
        {
            get
            {
                return this.policyName;
            }
            set
            {
               this.policyName = value;

            }
        }      
        [XmlAttribute]
        public PolicyTypes Type
        {
            get
            {
                return this.policyType;
            }
            set
            {
               this.policyType = value;

            }
        }           
    }

The Problem with this approach is that if later on I put any type other than type 1 or type 2, the XMLDeserializer will throw exception. so if i have the xml like

<PolicyDef name = "sample" type="type_new">
  <Options ......>
</PolicyDef>

The deserializer will throw error as type_new not valid.

I was wondering if there is a way to hook into the deserializer process to catch that and set a default value rather than throw error. Say if there is any invalid value, then I would set that to "type1"

Or am open to suggestions regarding how to handle this problem

Thanks and Regards

回答1:

This is possibly a duplicate of C# XML Deserialization W/ Default Values

Unfortunately it seems there is no way to fall back on default enum values during deserialisation. It will require slightly more work, but if you follow the linked example and implement IXmlSerializable in your PolicyDef class, you'll be able to implement the ReadXml method in a similar way (reflecting each of the properties using a try/catch block in order to check for a default value).

Hope that helps!



回答2:

Thanks Chris for the suggestion, but I don't want end up writing the complete parsing code which could be messy if the XML and corresponding class is huge and complex. I anyway used a different approach. I changed all the enum fields to string. In this case there would be no parsing error and then expose another property that would return the parsed value as enum and if the parsing fails, then return default enum value. E.g

private string policyName;
[XmlAttribute("Type")]
public string Type
{
    private get
    {
        return this.policyType;
    }
    set
    {
        this.policyType = value;
        try
        {
            this.PolicyType = (PolicyTypes)Enum.Parse(typeof(PolicyTypes), this.policyType);
        }
        catch(Exception)
        {
            this.PolicyType = PolicyTypes.DefaultPolicy;
        }
    }
}

public PolicyTypes PolicyType
{
    get;
    private set;
}

And use the class property to access the value rather than the xml attribute field.