Enumerated types (Enums) are a great thing especially when you’re coming from a background that didn’t have them as I do (and always cursed it back then). Enums allow you to easily set up ‘known values’ for an property or field that takes a fixed number of known values. Without Enums I used to use value codes (1 = this, 2 = that etc.) which is both cryptic to manage and doesn’t provide helpful information at runtime.
Enums are easy enough to create and use when you use single values. Assume the following enum:
public enum Processors
{
None,
AuthorizeNet,
PayPalPaymentsPro,
PayFlow,
LinkPoint
}
It’s then trivial to assign:
Processors ccProcessor = Processors.LinkPoint;
And then later check for a value match:
if (ccProcessor == Processors.LinkPoint)
{
... Do something with LinkPoint
}
Set Operations
What’s not quite so obvious is if you want to define set operations when you can have multiple values set. For example assume this assignment:
Processors ccProcessors = Processors.AuthorizeNet | Processors.PayFlow;
Now how do you check whether PayFlow is supported? First you have to set up the Enumeration a little differently so that it uses explicit values. Specifically the values defined for each of the items need to be mutually exclusive so that any two combinations can’t add up to a specific value.
public enum Processors
{
None = 0,
AuthorizeNet = 1,
PayPalPaymentsPro = 2,
PayFlow = 4,
LinkPoint = 8
}
This is necessary so that when you compare combinations they are always unique. The way to do this is to define values that double with every new value, 0,1,2,4,8,16,32,64,128 etc. If you don’t use explicit values like this .NET will assign values sequentially (0,1,2…) and this won’t work right for set based operations.
To check for a value is a little bit more tricky than a simple comparison. The easiest way is to use an exclusive AND:
if ( (ccProcessors & Processors.PayFlow) > 0 )
Response.Write("PayFlow");
if ( (ccProcessors & Processors.PayFlow) == 0)
Response.Write("Not PayFlow");
This doesn’t exactly roll of the tounge, but it works. Note that you HAVE TO use the parenthesis around the & expression, and you can only compare to 0! If the value is equal to 0 there’s no match, if it’s not equal there is. If you compare to 1 for example, you’ll get a compiler error telling you that you can’t compare an enumerator with an int. In this case 0 is used as a special case to indicate the bitstate of the expression.
I’m not particularly fond of this syntax and in fact it took me a little bit to remember it, which is why I’m writing this Blog entry to remind myself in the future <g>.
Enums can be turned into to string values:
string Type = ccProcessors.AccessPoint.ToString();
and they can also be easily parsed back into a value from a string:
ccProcessors Processor = (ccProcessors) Enum.Parse(typeof(ccProcessors), Type);
which makes it possible to generically load and write out Enum strings for the UI to use to display the values.
Parsing and listing Enums
I came into this yesterday in doing some work in my West Wind Web Store to add better support for Purchase Order Request for Purchase forms. The store previously worked with single entry enums which where combination values like:
public enum ccProcessingTypes
{
CreditCards,
CreditCardsAndPayPal,
None
}
Which worked fine for the two options. But now if you add a third choice the combinations get kinda cumbersome to express as individual Enum Values:
public enum ccProcessingTypes
{
CreditCards,
CreditCardsAndPayPal,
CreditCardsAndPurchaseOrders,
CreditCardsAndPayPalAndPurchaseOrders,
PayPalAndPurchaseOrders,
None
}
Obviously not the right choice of data structure here, especially if any more where added.
So I switched to this set up:
/// <summary>
/// Different combinations of Credit Card processing
/// options available in the store by default
/// </summary>
public enum CCProcessingTypes
{
None = 0,
CreditCards = 1,
PayPal = 2,
PurchaseOrders = 4;
All = 7
}
This required a few minor changes in the application itself which was easy to fix. However, what was not quite so quick to fix is allowing the user interface to choose the processing types. With the original option I could simply display the single value in a drop down list and allow my databinding directly to pick up the value and write back into the configuration object.
Now in this case, it’s not as easy as picking up the single value because it’s essentially a multi-selection option that needs to be written back into the underlying single Enum type.
To do this I used a CheckBoxList field on a Web form as there are only 3 values in this case and while 3 values are easy enough to deal with I used some code that’s somewhat generic to list out the values into the checkbox list and then save them back when the data is saved:
private void LoadCCProcessingTypes()
{
Array Types = Enum.GetValues( typeof(CCProcessingTypes));
foreach(CCProcessingTypes Type in Types)
{
if (Type == CCProcessingTypes.None || Type == CCProcessingTypes.All)
continue;
ListItem li = new ListItem();
li.Text = Type.ToString();
li.Value = ((int) Type).ToString();
if( (App.Configuration.CCProcessingType & Type ) > 0)
li.Selected = true;
this.txtProcessingType.Items.Add( li );
}
}
private void SaveCCProcessingTypes()
{
CCProcessingTypes Types = CCProcessingTypes.None;
foreach (ListItem li in this.txtProcessingType.Items)
{
if (li.Selected)
{
CCProcessingTypes Type = (CCProcessingTypes) int.Parse(li.Value) ;
Types = Types | Type;
}
}
App.Configuration.CCProcessingType = Types;
}
The key feature in the load code is the ability to easily get the values of the Enum with GetValues(). GetValues returns an array of the individual enum values that make up the Enum type. You can then use ToString() to get a string representation of the value or cast the value to an Int to get more of a Id value. Those items are then written into the ListItems as key value pairs.
You can also ccProcessingTypes.GetNames() which gets a string array (string[]) that contains just the text, which would have worked here too.
Once the user has made choices reading the values back is to loop through the list items, parse the selected value and then XOR it to the Enum structure.
Another way to do this is add the integer values together and simply assign the value to the enum and cast it:
App.Configuration.CCProcessingType = (CCProcessingTypes) x;
Enums are one of those features that are ‘just there’ in .NET but they afford a lot of flexibility. I often wonder how I ever got along without them in pre-.NET days.
Other Posts you might also like