#1,026 – Checking a Flagged enum Type for Validity

You normally use the Enum.IsDefined method to check whether a particular enum value is a valid value.  This method does not work on flagged enums.

Assuming the following enum type:

    [Flags]
    public enum Talents
    {
        Singing = 1,
        Dancing = 2,
        Juggling = 4,
        JokeTelling = 8
    };

Enum.IsDefined will not work for all values of the flagged enum:

            Talents myTalent = Talents.JokeTelling | Talents.Juggling;
            // Returns false
            bool isDefCheck = Enum.IsDefined(typeof(Talents), myTalent);

To properly check for validity, you can convert the enum to a string and then try parsing as an integer. If the value is invalid, ToString() will convert to a simple integer and the parse will then succeed.

        private static void CheckTalents(Talents t)
        {
            int intTest;
            if (int.TryParse(t.ToString(), out intTest))
                Console.WriteLine("Talents not ok");
            else
                Console.WriteLine("Talents ok");
        }

1026-001

Advertisement

#1,025 – Converting between enum Types

You can convert between two different enum types as long as they both use the same underlying type (e.g. int).  You use an explicit cast to do the conversion.

Assuming two enum types that by default use int as their underlying type, e.g.:

    public enum Day { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
    public enum Dinner { Sausages, Mutton, Tacos, Wontons, ThinMints, FriedEggs, Sandwiches }

You can convert between them using a simple cast:

            Day today = Day.Monday;
            Dinner menuTonight = (Dinner)today;
            Console.WriteLine("Today is {0} and I'm having {1} for dinner", today, menuTonight);

1025-001

#982 – An Enum Type Can Store a Maximum of 32 Flags

When you store a boolean value in a bool type, each boolean value uses 1 byte, or 8 bits–the size of a bool instance.

You can be more efficient in storing boolean values by using each bit within a chunk of memory to represent a single boolean value.  You can do this quite easily by using an enum type to store a series of flags.  In the example below, a single value of type Talents can represent unique values for up to 8 different boolean values.

        [Flags]
        public enum Talents
        {
            Singing = 1,
            Dancing = 2,
            Juggling = 4,
            JokeTelling = 8,
            DoingMagic = 16,
            RollingTongue = 32,
            StiltWalking = 64,
            DoingSplits = 128
        };

You can set various bits using the bitwise OR operator.

            Talents myTalents = Talents.JokeTelling | Talents.Juggling | Talents.StiltWalking;

            // 76 = 8 + 4 + 64
            int asInt = (int)myTalents;

Note that you can store a maximum of 32 different flags in an enumerated type, because an enum type uses 4 bytes (32 bits) of storage.

#626 – Nested Type Options

When you declare one type inside of another, the outer type must be either a class or a struct.  The inner (nested) type can be one of the following: class, struct, interface, delegate or enum.

Here are a few common examples.

A struct in a class:

    public class Dog
    {
        public string Name { get; set; }

        public struct DogCollar
        {
            public int Length;
            public string Material;
        }
    }

A delegate type  defined in a class:

    public class Dog
    {
        public string Name { get; set; }

        public delegate void BarkHandler(object sender, BarkEventArgs e);
    }

An enum in a class:

    public class Dog
    {
        public string Name { get; set; }

        public enum Temperament { Docile, Excitable, Vicious };
    }

#464 – Getting an Enumeration’s Underlying Type at Runtime

You can use the Enum.GetUnderlyingType static method to find out what the underlying type is that is being used to store an enumerated type’s enumerated values.

        public enum Moods : byte
        {
            NOMOOD = 0,
            Ambivalent = 1,
            Crabby = 10,
            Grouchy = Crabby - 1,
            Happy = 42,
            SuperHappy = 2 * Happy
        }

        static void Main()
        {
            Type moodStorageType = Enum.GetUnderlyingType(typeof(Moods));
            var min = moodStorageType.GetField("MinValue").GetValue(null);
            var max = moodStorageType.GetField("MaxValue").GetValue(null);

            Console.WriteLine("Underlying type for Moods is: {0}", moodStorageType.FullName);
            Console.WriteLine("Values can range from {0} to {1}", min, max);
        }

#463 – Enumerated Values Can Be Any Constant Expression

When you define an enum, the individual values can be implicitly defined (one greater than the previous value), assigned to a constant, or assigned to any constant expression.

In the definition of the Moods enumerated type below, constant expressions are used for some of the values.

        public const int HappyFactor = 42;

        public enum Moods
        {
            NOMOOD = 0,
            Ambivalent = 1,
            Crabby = 10,
            Grouchy = Crabby - 1,
            Happy = HappyFactor,
            SuperHappy = 2 * Happy
        }

#462 – Duplicate Enumerators in an Enumerated Type

When defining a new enumerated type, you can define multiple enumerators that have the same underlying value.  You might do this when you have a finite set of enumerated values and you want to map them to a smaller finite set of internal values.

In the example below, we have six different MovieRatings values, internally.  But we define 10 different enumerators for the type, so some of them end up mapping to the same value.

        public enum MovieRatings
        {
            DidntSeeIt = 0,
            NONE = 0,
            Crappy = 1,
            Horrible = 1,
            Watchable = 2,
            Average = 3,
            Good = 4,
            SeeIt = 4,
            Great = 5,
            MustSee = 5
        };

#461 – Enumeration Elements Don’t Need to Be Sequential

Enumeration elements are implicitly set to consecutive integers, starting at 0, as indicated in the comments below.

        // Default type is int
        public enum Mood
        {
            Crabby,      // 0
            Happy,       // 1
            Petulant,    // 2
            Elated       // 3
        };

You can also assign any values you like to the constants.

        public enum Mood
        {
            Crabby = -50,
            Happy = 80,
            Petulant = -20,
            Elated = 99
        };

You can define these constants in any order. They don’t have to be sequential.

        public enum Days
        {
            Friday = 5,
            Monday = 1,
            Saturday = 6,
            Sunday = 0,
            Thursday = 4,
            Tuesday = 2,
            Wednesday = 3
        };

#460 – Converting from a String to an Enum Type

You can convert a string to the corresponding enumerator in an enum type by using the Enum.Parse method.  This is a static method that takes the specific enumerated type and a string value and returns the corresponding enumerated value of the type.

        public enum Mood { Crabby, Happy, Petulant, Elated };

        static void Main()
        {
            string myMood = "elated";
            Mood mood = (Mood)Enum.Parse(typeof(Mood), myMood, true);

        }

The third parameter indicates whether case should be ignored when searching for a value.

Because Enum.Parse returns a value of type object, you need to cast the return value to the desired enumerated type.

If an enumerator in the enum type that matches the specified string value can’t be found, the method will throw an ArgumentException.

#459 – Assigning a Value of a Different Type to an enum

You can convert to an enum value from its underlying type by casting the underlying type (e.g. int) to the enum type.  You can also assign a value of a different type, one that does not match the underlying type, as long as the cast succeeds.

        // By default stored as int, with values 0,1,2,3
        public enum Mood { Crabby, Happy, Petulant, Elated };

        static void Main()
        {
            byte moodValue = 3;
            Mood mood;

            // Works (byte -> int)
            mood = (Mood)moodValue;

            // Also works, since cast converts value to 2 (Petulant)
            double moodValue2 = 2.1;
            mood = (Mood)moodValue2;
        }