Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

Enums, Enum Sets, parsing n' stuff


:P
On this page:

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.


The Voices of Reason


 

Joe Brinkman
June 30, 2006

# re: Enums, Enum Sets, parsing n' stuff

Rick,
You can make this a bit easier using the FlagsAttribute which automatically creates the appropriate values in your enumeration. I found a good blog that summarizes it's use: http://weblogs.asp.net/wim/archive/2004/04/07/109095.aspx

There is also good information in the MSDN docs on why to use the flagsattribute beyond just the bit setting: ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.en/cpref2/html/T_System_FlagsAttribute.htm

Rick Strahl
June 30, 2006

# re: Enums, Enum Sets, parsing n' stuff

Thanks Joe, I wish I would have seen this yesterday and I wouldn't have posted this. I was looking around for a bit didn't find anything so I thought I'd write it up.

Looks though from the comments on that post that [Flags] and [FlagsAttribute] is not reliable by itself and you do still need the value. I did look at the [Flags] value but I couldn't really see what the reason for using it is if you have to override the values anyway.


Gabriel Lozano-Morán
June 30, 2006

# re: Enums, Enum Sets, parsing n' stuff

The purpose of the FlagsAttribute is not to have the compiler set the values for you during compilation instead it is used to declartively indicate that the enum can be treated as a bit field. An example of this in the Framework Class Library is the enumeration System.Reflection.BindingFlags


Steve from Pleasant Hill
June 30, 2006

# re: Enums, Enum Sets, parsing n' stuff

All of this makes me long for my Pascal days...

Jason Haley
July 01, 2006

# Interesting Finds: July 1, 2006 AM edition


Kim
July 02, 2006

# re: Enums, Enum Sets, parsing n' stuff

For anyone unfamiliar with bitmasks (or need a refresher) the following two links are good reference material as well as the blog entry mentioned above.
http://www.codeproject.com/cpp/bitbashing.asp
http://www.codeproject.com/useritems/Binary_Guide.asp


Random Reader
July 04, 2006

# re: Enums, Enum Sets, parsing n' stuff

Online version of what Joe Brinkman was referring to: http://msdn2.microsoft.com/en-us/library/system.flagsattribute

The example code there shows how the ToString() behavior changes when FlagsAttribute is present.

Rick Strahl
July 04, 2006

# re: Enums, Enum Sets, parsing n' stuff

Actually the ToString() behavior changes when you assign a fixed value and the value rather than the enum string representation is returned.

There are some great related links posted here! I certainly can use an occasional refresher on binary math <g>...

To summarize the [Flags] attribute is used to have .NET treat the enum as a single byte. Hence, the size limtitation to values of 255 or less.

Otherwise the behavior of assigning explicit values seems to be identical. The advantage is if you can represent the values with [Flags] is that memory usage is reduced...

Random Reader
July 04, 2006

# re: Enums, Enum Sets, parsing n' stuff

I'm not sure what you mean about the fixed value assignment. To clarify, using your Processors enum example:

static void Main()
{
Processors ccProcessors = Processors.AuthorizeNet | Processors.PayFlow;
Console.WriteLine("enum {0} (storage: {1}) has value {2}",
ccProcessors.GetType().Name,
Enum.GetUnderlyingType(typeof(Processors)).Name,
ccProcessors.ToString());
}

Without [Flags]:
>> enum Processors (storage: Int32) has value 5

With [Flags]:
>> enum Processors (storage: Int32) has value AuthorizeNet, PayFlow

Note that FlagsAttribute has no bearing on the storage size. I'm not sure what you saw that implied the size limitation; that choice is actually directed by the compiler. C# exposes it as an inheritence-style syntax, defaulting to int. To have the Processors enum use a byte for storage:

public enum Processors : byte { ... }

FlagsAttribute only affects ToString() as far as the Enum class itself is concerned; this can be verified using the SSCLI sources. I'd expect to affect parsing as well, but alas, parsing always treats it as a bitmask.

I don't know if FlagsAttribute is handled specially by anything else in the Framework itself, although various tools probably do make use of it. It would be important for debuggers, for example. It's one of those attributes that you use to clearly document the semantics of what you're doing, even if it has no real effect on your results.

I do wish the C# compiler supported it better. As the comments in Joe Brinkman's first link note, it doesn't prompt the C# compiler to automatically step the values in bit increments; it still does the previous+1 thing, which is almost always the wrong behavior, so you're forced to specify the values yourself. Oh well.

Random Reader
July 04, 2006

# re: Enums, Enum Sets, parsing n' stuff

I actually meant to write the GetUnderlyingType line as:

Enum.GetUnderlyingType(ccProcessors.GetType()).Name

It does the same thing for that code, but less code maintenance if you later change the enum type. Plus it's a neat example of type inpection :)

Steve
July 05, 2006

# re: Enums, Enum Sets, parsing n' stuff

Speaking of bitmasks above.. this is an excellent excellent excellent blog entry on it

http://www.johnsample.com/articles/BitwiseEnums.aspx

# A Continuous Learner's Weblog: C# and VB.NET Links

# DotNetSlackers: Enums, Enum Sets, parsing n' stuff


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024