Reputation: 146559
If I have a flagged enum lets say for argument
[Flags]
public enum Shipping { Null=0x00, FedX=0x01, UPS=0x02, AirBrn=0x04, USPS=0x08, Any=0xFF}
and I want to store this value in an Xml config file, such as
[XmlAttribute(AttributeName="shipper")]
public Shipping ShippingOption { get; set; }
I know that I have to separate combined values with a space, for example, If I want the config file to represent ShippingOption as either FedX or UPS, then the Xml would look like this:
<ElementName shipper="FedX UPS" />
or if I want it to represent FedX or UPS or USPS then
<ElementName shipper="FedX UPS USPS" />
But what do I put in the attribute if I want it to be anything but UPS?
(Assuming the enum does not have a predefined value for this (like Shipping.Any
)
This would be the equivalent of c# value
var ship = Shipping.Any & ^Shipping.UPS;
I know I could just leave out the one I don't want, like this:
<ElementName shipper="FedX USPS AirBrn " />
But if there are many many members in the Enum that gets tedious, (and would require maintenance anytime the complete list expanded). Is there a short hand way to represent Negation of a flagged Enum ?
Upvotes: 1
Views: 822
Reputation: 149040
Here's a fairly crude solution that should work. First, write a method to parse your custom enum syntax—in my implementation, ~X
means '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;
}
And here's a very simple format function that's compatible with the original XML serialization:
private string FormatEnum<T>(T s) where T : struct, IConvertible
{
return s.ToString().Replace(",", "");
}
Now just set up a proxy property wherever you need to use this and make sure you mark the original with XmlIgnore
:
[XmlIgnore]
public Shipping ShippingOption { get; set; }
[XmlAttribute(AttributeName = "shipper")]
public string ShippingOptionString
{
get { return FormatEnum<Shipping>ShippingOption); }
set { ShippingOption = ParseEnum<Shipping>(value); }
}
Now it will be able to correctly parse XML like this:
<ElementName shipper="Any ~UPS" />
Other solutions exist for different serialization libraries, but the pattern would basically be the same. Deserialize a the XML attribute as string, then parse it using your custom parser to get the enum result you want.
Upvotes: 1