如何在XML配置文件中表示复合Flagged Enum值

时间:2016-12-22 22:01:42

标签: c# .net xml enums flags

如果我有一个标记的枚举,请说出参数

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

我知道我必须将组合值与空格分开,例如,如果我希望配置文件将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中有许多成员变得单调乏味,(并且随着整个列表的扩展需要维护)。是否有一种简短的方法来表示被标记的枚举的否定?

1 个答案:

答案 0 :(得分:1)

这是一个应该有效的原始解决方案。首先,编写一个解析自定义枚举语法的方法 - 在我的实现中,~X表示&#39;而不是X&#39;:

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属性反序列化为字符串,然后使用自定义解析器解析它以获得所需的枚举结果。