如何在 XML 配置文件中表示复合标记枚举值

How to represent composite Flagged Enum values in XML config file

如果我有一个标记的枚举让我们说参数

[Flags]
public enum Shipping { Null=0x00, FedX=0x01, UPS=0x02, AirBrn=0x04, USPS=0x08, Any=0xFF}

我想将此值存储在 Xml 配置文件中,例如

  [XmlAttribute(AttributeName="shipper")]
  public Shipping ShippingOption { get; set; }

我知道我必须用 space 分隔组合值,例如,如果我希望配置文件将 ShippingOption 表示为 FedX 或 UPS,那么 Xml 看起来像这个:

  <ElementName shipper="FedX UPS" />

或者如果我想让它代表 FedX 或 UPS 或 USPS 那么

  <ElementName shipper="FedX UPS USPS" />

但是如果我希望它不是 UPS,我应该在属性中输入什么? (假设枚举没有为此预定义的值(如 Shipping.Any) 这相当于 c# value

       var ship = Shipping.Any & ^Shipping.UPS;

我知道我可以忽略我不想要的那个,像这样:

 <ElementName shipper="FedX USPS AirBrn " /> 

但是如果 Enum 中有很多成员会变得乏味,(并且在完整列表展开时需要随时维护)。是否有一种简写方式来表示已标记枚举的否定?

这是一个应该可行的相当粗略的解决方案。首先,编写一个方法来解析您的自定义枚举语法——在我的实现中,~X 表示 'and not X':

private T ParseEnum<T>(string str) where T : struct, IConvertible
{
    var result = 0;
    foreach (var name in str.Split())
    {
        if (name.StartsWith("~"))
        {
            result &= ~(int)(Enum.Parse(typeof(T), name.Substring(1), true));
        }
        else
        {
            result |= (int)(Enum.Parse(typeof(T), name, true));
        }
    }

    return (T)(object)result;
}

这里有一个非常简单的格式函数,它与原始的XML序列化兼容:

private string FormatEnum<T>(T s) where T : struct, IConvertible
{
    return s.ToString().Replace(",", "");
}

现在只需在需要使用它的任何地方设置代理 属性 并确保将原始标记为 XmlIgnore:

[XmlIgnore]
public Shipping ShippingOption { get; set; }

[XmlAttribute(AttributeName = "shipper")]
public string ShippingOptionString
{
    get { return FormatEnum<Shipping>ShippingOption); }
    set { ShippingOption = ParseEnum<Shipping>(value); }
}

现在它将能够像这样正确解析 XML:

<ElementName shipper="Any ~UPS" />

针对不同的序列化库存在其他解决方案,但模式基本相同。将 XML 属性反序列化为字符串,然后使用自定义解析器解析它以获得所需的枚举结果。