如何在C#中序列化/反序列化可选的XML枚举?

7

我正在尝试弄清如何将带有可选枚举类型属性的XML列表序列化/反序列化到C#中。以下是我的C#类:

public class AttributeAssignmentExpressionElement : XACMLElement
{
    [XmlAttribute]
    public string AttributeId { get; set; }

    [XmlAttribute]
    public Category Category { get; set; }                   
}

我的类别枚举定义如下:

public enum Category
{
    [XmlEnum(Name = "urn:oasis:names:tc:xacml:1.0:subject-category:access-subject")]
    Subject,
    [XmlEnum(Name = "urn:oasis:names:tc:xacml:3.0:attribute-category:resource")]
    Resource,
    [XmlEnum(Name = "urn:oasis:names:tc:xacml:3.0:attribute-category:action")]
    Action,
    [XmlEnum(Name = "urn:oasis:names:tc:xacml:3.0:attribute-category:environment")]        
    Environment
}  

当相应的XML文件中存在Category时,序列化/反序列化按预期工作。但是,如果XML中缺少Category,则使用默认值(枚举中的第一个项)。如果我尝试使枚举变量可空(Category?),反序列化程序会抛出异常,因为它无法反序列化复合类型。给定以下不包含属性的XML,如何适当地序列化枚举?
<AttributeAssignmentExpression
    AttributeId="urn:oasis:names:tc:xacml:3.0:example:attribute:text">       
</AttributeAssignmentExpression>

在这种情况下,反序列化对象中的值应为null。
感谢您能提供的任何帮助!
3个回答

15

嗯,你可以这样做 - 但有点混乱:

[XmlIgnore]
public Category? Category { get; set; }

[XmlAttribute("Category")]
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public Category CategorySerialized
{
    get { return Category.Value; }
    set { Category = value; }
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public bool ShouldSerializeCategorySerialized()
{
    return Category.HasValue;
}

这段代码的作用:

  • 使用一个可选的枚举值 Category?
  • 禁止序列化 Category 属性
  • 添加了一个辅助属性 CategorySerialized 来代理 Category,它是非空的并且能够在IDE等中被隐藏(尽可能地)
  • 通过 ShouldSerialize* 模式使用条件序列化在 CategorySerialized

这与 XSD 的写法接近,如果您从模式开始(我建议这样做),则不需要为实际值拥有单独的属性。只需使用可空类型即可。 - Malcolm
实际上 - 我使用XmlIgnore属性实现了与此非常相似的东西...我希望有一种更简洁的方法。看起来这是唯一的方法。谢谢! - Rockdocta

4
实际上,有一些官方的方法可以实现这个功能(在这里看):

另一个选项是使用特殊的模式创建一个被XmlSerializer识别的Boolean字段,并将XmlIgnoreAttribute应用于该字段。该模式采用propertyNameSpecified的形式创建。例如,如果存在名为"MyFirstName"的字段,则还需创建一个名为"MyFirstNameSpecified"的字段,以指示XmlSerializer是否生成名为"MyFirstName"的XML元素。下面的示例显示了这种情况。

也就是说,在TS案例中,模型应该像这样:
public class AttributeAssignmentExpressionElement : XACMLElement
{
    [XmlAttribute]
    public string AttributeId { get; set; }

    [XmlAttribute]
    public Category Category { get; set; }

    [XmlIgnore]
    public bool CategorySpecified { get; set; }                   
}

除非您将魔术字段CategorySpecified设置为true,否则Category属性不会被序列化。在反序列化的情况下,CategorySpecified将为false,表示XML中未包含Category


3
使用“Specified”模式的完整示例代码。
public class ClassToSerialize
{
    [XmlAttribute("attributeName")]
    public EnumType EnumPropertyValue
    {
        get { return EnumProperty.Value; }
        set { EnumProperty = value; }
    }
    [XmlIgnore]
    public EnumType? EnumProperty { get; set; }
    public bool EnumPropertyValueSpecified => EnumProperty.HasValue;

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接