【问题标题】:How to serialize/deserialize optional XML enumeration in C#?如何在 C# 中序列化/反序列化可选 XML 枚举?
【发布时间】:2012-05-31 19:39:39
【问题描述】:

我试图弄清楚如何将 XML 列表序列化/反序列化为 C#,该列表具有枚举类型的可选属性。以下是我的 C# 类:

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

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

我的Category枚举定义如下:

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
}  

Category 出现在相应的 XML 文件中时,序列化/反序列化按预期工作。但是,如果 XML 中缺少 Category,则使用默认值(枚举中的第一项)。如果我尝试将枚举变量设为可空 (Category?),则反序列化程序会抛出异常,因为它无法反序列化复杂类型。给定以下 XML(不包含该属性),如何适当地序列化枚举?

<AttributeAssignmentExpression
    AttributeId="urn:oasis:names:tc:xacml:3.0:example:attribute:text">       
</AttributeAssignmentExpression>

在这种情况下,反序列化对象中的值应该为null。

感谢您提供的任何帮助!

【问题讨论】:

    标签: c# xml xml-serialization


    【解决方案1】:

    好吧,你可以这样做 - 但它有点乱:

    [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 所写的内容很接近,但您不需要为实际值设置单独的属性。只需使用可空类型。
    • 实际上 - 我使用 XmlIgnore 属性实现了一些与此非常相似的东西..我希望有一种更清洁的方式。看来这是唯一的办法了。谢谢!
    【解决方案2】:

    实际上,有一些官方的魔法可以做到这一点 (see here):

    另一种选择是使用特殊模式来创建 XmlSerializer 识别的布尔字段,并将 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,表示Category 不存在于 XML 中。

    【讨论】:

      【解决方案3】:

      使用“指定”模式的完整示例代码

      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;
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-30
        • 2021-11-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多