Tag Archives: enum

Performance and Other Issues with System.Enum

I’ve been doing a lot of very intense .Net coding at work for the last few months and it’s very gratifying to see that .Net can handle some pretty serious high-load scalable server work. We are doing some pretty amazing things. However, there are all sorts of gotchas—you do have to learn how to do it correctly (but that’s true of any technology).

One of the things we’re most concerned about right now is performance, and where performance is concerned, one of the big gotchas is the .Net Framework Class Library. Don’t get me wrong, for 99.99% of all .Net projects, the performance is perfectly adequate and you don’t have to care (much). On the other hand, if you’re dealing with highly-scalable systems, you should definitely validate the performance of any general-purpose library you use.

As with all performance question, the only 100% solid advice in all situations is: measure, measure, measure.

General Purpose Methods May Not Be Fast

I did a profiler run on one of our components the other day and a few methods showed up that I would never expect to see in a profiler trace:

We were calling these methods a lot. In my mind, they both basically boiled down to logical AND (&) statements. Unfortunately that’s not the case.

If you use an IL decompiler like ILSpy to examine the code of these methods, you’ll see they do quite a bit more. For example, HasFlag also checks whether the types are equal—useful, but that’s a lot more expensive than a simple & check.

IsDefined is even worse. There are half a dozen checks for specific types, followed by an allocation of an array containing all the enum values, and finally a binary search. If your enums are string types, then it’s just a linear search with string comparisons.

It’s easy to understand why these methods are so heavy—they’re being extra cautious for correctness-sake. That’s probably what you want in a general-purpose framework.

However, if your goal is performance and you have a closed system, complete control of your code, and adequate tests, then you can make better decisions.

Rather than do this:

if (bookFlags.HasFlag(BookTypes.Fiction))

Do this instead:

if ((bookFlags & BookTypes.Fiction) != 0)


As for IsDefined, just don’t use it. Or use it in debug-only assertions to validate functionality.

Another Enum method to avoid if you can is ToString(), especially on enumerations that have [Flags].

HasFlag Gotcha

Suppose you have this code:

[Flags]
enum NodeFlags
{
    Exception = 1,
    Failure = 2,
    Canceled = 4,
    TimedOut = 8,
 
    AnyFailure = Exception | Canceled | TimedOut
}
 
if (node.Flags.HasFlag(NodeFlags.Failure)
    || node.Flags.HasFlag(NodeFlags.TimedOut)
    || node.Flags.HasFlag(NodeFlags.Exception))

You may be tempted to do this:

if (node.Flags.HasFlag(NodeFlags.AnyFailure))

This will not work. It will check that ALL of the bits are set, not just one of them.

You will need to do this:

if ((node.Flags & NodeFlags.AnyFailure) != 0)

We saw that around 5% of our CPU time was being spent just in Enum.IsDefined and Enum.HasFlag. With these changes, we reduce that to approximately 0.

If you find tips like these helpful, you’ll love my book, C# 4.0 How-To.

Checking all values of an enumeration in C#

I have a utility function that takes in a status enumeration and returns a string description associated with the given status code.

It looks something like this:

internal static string MailProcessCodeToString(MailProcessCodes eCode)
{
switch (eCode)
{
case MailProcessCodes.mpcGoodData:
    return “No errors detected in the order mail”;case MailProcessCodes.mpcNoHeader:
    return “Could not find header in order mail”;

//etc….
I wanted to create a unit test that ensure there was an error message for every possible value of the eCode. Rather than write a separate unit test for each value (there are over 30–don’t ask).It’s fairly easy to do in .Net (using NUnit):

[Test]
public void MailProcessCodeToString_AllSuccess()
{
   
int[] vals = (int[])Enum.GetValues(typeof(MailProcessCodes));
   
foreach (int val in vals)
    {
       
string errorString = Utils.MailProcessCodeToString((MailProcessCodes)val);       

        string msg = string.Format(“{0} has no error string defined”,
                      
Enum.GetName(typeof(MailProcessCodes), val));        Assert.IsTrue(errorString.Length > 0, msg);
    }
}

Enum.GetValues() returns an array of all defined values for an enum, and Enum.GetName() translates a value into the name of the constant.

Now I have a unit  test which will tell me which error code does not have a corresponding string.