Gururaj’s Rumination

Rumination – The word says it all…

Enum.IsDefined and Performance issue

with 2 comments

Till today I’d never used Enum.IsDefined method to verify whether a value is defined in a given Enum. My first encounter with Enum.IsDefined happened a day or two before when I stumbled on this while analyzing existing code for performance loopholes. I found a method which happened to verify whether a value is defined in the given Enum and flag if it’s not. I’d never imagined that Enum.IsDefined can be so expensive that the performance of the component will go down exponentially based on the volume of the data it has to process. To understand better why it’s expensive lets first understand Enum.

Enum is a ValueType and every Enum derives implicitly from System.Enum and this in turn derives from ValueType. To understand in more detail here is the extracted description from the C# Language Specification

11.1.9 Enumeration types

An enumeration type is a distinct type with named constants. Every enumeration type has an underlying type, which shall be byte, sbyte, short, ushort, int, uint, long or ulong. Enumeration types are defined through enumeration declarations (§21.1). The direct base type of every enumeration type is the class System.Enum. The direct base class of System.Enum is System.ValueType.

Given the definition, the below code snippet declares a ‘Status’ enum type. And from definition the underlying type of ‘Status’ type will be Int32. This means that ‘InProgress’ is named a constant for value 0 and ‘Success’ is named constant for value 1 followed by ‘Failed’ as 2. The point to be noted here is that the first named constant always starts with 0 and the subsequent constants have incremental value.

                enum Status
                {
                                InProgress,
                                Success,
                                Failed,
                }

The declaration can also be changed to make ‘InProgress’ to represent 1, ‘Success’ as 2 and ‘Failed’ as 3 as shown below.

                enum Status
                {
                                InProgress = 1,
                                Success,
                                Failed,
                }

And few of its usage looks like (using the first declaration)

            Status status = Status.Success;
            Status status = (Status) 0;
            Status status = (Status) -1;

The last assignment may seem erroneous but it will neither throw compile-time or run-time exception. This might seem like a bug but it’s just design (see Enumeration Type definition from the C# Language specification above.)

Now coming to core of the topic, in the simplest terms the Enum.IsDefined verifies whether the supplied value is defined in the give Enum Type or not. But looking at the Enum.IsDefined method signature it’s evident that it internally uses Reflection and also  Boxing to determine whether the supplied value is of enumType of not. On top of this it also verifies whether value is of type enumType or not. This mean there is more logic involved than just verifying the data.

            Enum.IsDefined(Type enumType, object value);

In simple scenarios where one has to verify a single value against an Enum using Enum.IsDefined may not be harmful. But in a scenario where list of values has to be validated this method can lead to performance issues. There may be different ways to check for value in the enum like using switch statement

                private bool IsDefinedInEnum(Status _status)
                {
                                switch(_status)
                                {
                                                case Status.InProgress:
                                                break;

                                                case Status.Success:
                                                break;

                                                default:
                                                //This safely can be assumed Failed
                                                break;
                                }
                }

The problem with this approach is what if in the later stage ‘Aborted’ is added to the ‘Status’ enum – the logic fails unless the method is extended to include the new symbolic constant – this can be termed as versioning issue. The other way to verify is to check for range rather walking through the enum constants. Again, this approach too can run into problem if a new constant is added to the enum.

            private bool IsDefinedInEnum(Status _status) 
           
{
                        return (_status >= Status.InProgress && _status <= Status.Failed);
            }

This approach has definitely helped me fix the performance issue I’d seen in my project but may fail in case of Bitwise ORed value like

                [Flags]
                enum Status
                {
                                InProgress,
                                Success,
                                Failed,
                                Aborted,
                }

            Status status = Status.Aborted | Status.Failed;

Conclusion: Try avoiding Enum.IsDefined as much as possible and look for simpler and better approach to verify the value.

Advertisements

Written by Gururaj

December 24, 2008 at 9:57 pm

Posted in Technology

Tagged with , ,

2 Responses

Subscribe to comments with RSS.

  1. i hate enums. they are SO badly written….. and what the hell is this shit? why do we need to vertify enums? why don’t they bounded to there’s values by themself…..

    Itay

    November 2, 2009 at 3:26 am


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: