Click here to Skip to main content
15,884,473 members
Articles / Programming Languages / C#
Article

Enums Multivaluables

Rate me:
Please Sign up or sign in to vote.
2.86/5 (18 votes)
27 Mar 2006CPOL2 min read 39.2K   371   16   7
This article describes how to pass more than one value of an enum in a single variable or call

Introduction

Working with enums is a very interesting option in several situations, that one that I prefer the most is to avoid hardcoding a string. Another interesting one for me is the possibility of modifying the behaviour of a class or a control giving it a sequence of orders with an enum that accepts more than one value.

The Source of the Idea

The first time when I was developing with Reflection, I discovered the way the System.Type.GetType().GetMethod() method has a parameter whose type is the enum System.Reflection.BindingFlags, and this method accepts more than one value or the Enum if necessary to specify the behaviour of the method.

C#
//Example of BindingFlags Enums 
System.Collections.ArrayList list = new System.Collections.ArrayList ();
System.Type type = list.GetType();
System.Reflection.MethodInfo mi = type.GetMethod 
	( "Sort", System.Reflection.BindingFlags.IgnoreCase | 
	System.Reflection.BindingFlags.Public );
mi.Invoke ( list, new object [] { } );

Background

When I saw the values of the members of the enums and some documentation about it, I clearly noticed that the trick is to develop an enum with values such that the addition of any combination is unique.

This is the way most of the .NET Framework enums are defined. To be precise, most of those that I have seen, as for example the Binding Flags enum, are defined with values in a series of 2^n, having 0 as default value.

C#
// Examples of Enums that can be used as Multivaluables
/// <summary>
/// Integer Enum, whose values are 2^n.
/// </summary>
public enum PlanesTypes
{
    NoPlane           = 0,    //000000
    F15_Eagle        = 1,     //000001
    F18A_Hornet     = 2,      //000010
    F14                 = 4,  //000100
    MIG29_Fulcrum  = 8,       //001000
    F16_Falcon       = 16,    //010000
    F127_Phantom   = 32       //100000
}

/// <summary>
/// Integer Enum, whose values are 2^n.
/// </summary>
public enum DaysOfWeek
{
    NoDay          = 0,      //0000000
    Monday         = 1,      //0000001
    Tuesday        = 2,      //0000010
    Wednesday    = 4,        //0000100
    Thursday       = 8,      //0001000
    Friday           = 16,   //0010000
    Saturday       = 32,     //0100000
    Sunday         = 64      //1000000

Declare an enum this way, you always can add as many values of the enum as you like and you can be sure you will be able to recover the selected values when needed.

C#
// You can Pass to a method one or more Values as a single Parameter
// Here a logical sum is being done when the | operator is used
//Thursday + Wednesday + Monday + NoDay

SetMyFavoriteDaysOfTheWeek ( ( DaysOfWeek ) 13 ); 
SetMyFavoriteDaysOfTheWeek 
	( DaysOfWeek.Friday | DaysOfWeek.Saturday | DaysOfWeek.Sunday );
SetMyFavoriteDaysOfTheWeek ( DaysOfWeek.Saturday | DaysOfWeek.Sunday );
SetMyFavoriteDaysOfTheWeek ( DaysOfWeek.Monday | DaysOfWeek.Tuesday | 
	DaysOfWeek.Wednesday | DaysOfWeek.Thursday | DaysOfWeek.Friday );

What I have done is a static function that given an enumType and a value returns a System.Collections.ArrayList with the values resulting from desegregating the enum value given as a parameter.

C#
public class EnumReader
/// <summary>
/// Summary description for EnumReader.
/// </summary>
public class EnumReader
{
    /// <summary>
    /// This Method transform Transforms the Multivalue value of an enum in an
    ///  ArrayList that contains
    /// the singles values.
    /// </summary>
    /// <param name="EnumType">Type of the Enum</param>
    /// <param name="EnumValue">Multivalue value of the Enum</param>
    /// <returns>ArrayList with as many elements as Values contained 
    /// in the Multivalue</returns>
    public static System.Collections.ArrayList GetValuesFromEnum 
	( System.Type EnumType, int EnumValue )
    {
        System.Array EnumValues = System.Enum.GetValues ( EnumType );
        System.Collections.ArrayList valuesList = 
		new System.Collections.ArrayList ( EnumValues.Length );
        System.Collections.ArrayList SelectedList = 
			new System.Collections.ArrayList ( );        
        System.Collections.IEnumerator enumerator = EnumValues.GetEnumerator();
        while ( enumerator.MoveNext() )
            valuesList.Add ( ( int ) enumerator.Current );
        
        valuesList.Sort ( new ReverseOrder() );        
        enumerator = valuesList.GetEnumerator();
        while ( enumerator.MoveNext() )
        {
            if ( EnumValue >= ( int ) enumerator.Current )
            {
                EnumValue -= ( int ) enumerator.Current;
                SelectedList.Add ( ( int ) enumerator.Current );
            }
        }
        return SelectedList;
    }
    /// <summary>
    /// Implements IComparer to Sort in a Reverse Order.
    /// From the Bigger to the Smaller of the Values.
    /// </summary>
    internal class ReverseOrder : System.Collections.IComparer
    {
        public int Compare ( object x, object y )
        {
            return ( ( int ) y ).CompareTo ( ( int ) x );
        }
    }
} 

In the image below, it can easily be seen that the binary addition can be decomposed in the single values of the enum. And it is also clear that if the values of the enum are declared as 2^n, the result of the addition of any combination of values are unique.

Sample Image - MultivaluableEnums.jpg

Create an enum this way using a function like this. It is very easy to create behaviours on classes, controls or avoid arrays with many values.

In my case, I have an ASCX control with 7 different divs that contain radio buttons, checkboxes with prices, and specific information (and there are a lot of combinations with 7 elements) that must be shown or hidden depending on specific and complex business rules, so I thought that putting an integer value in a member of a Business Entity was a clear and easy way to do it, because in the end you are adding Integer values.

That's all. I hope someone finds it useful.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Australia Australia
Spanish Computer Engineer who is working with Microsoft Technologies.

Currently working and living in Sydney, Australia.

Comments and Discussions

 
GeneralMy vote of 4 Pin
Kevin-Brunner9-Aug-12 7:32
professionalKevin-Brunner9-Aug-12 7:32 
good
GeneralUmmmm... Pin
shaul_ahuva17-Feb-06 3:27
shaul_ahuva17-Feb-06 3:27 
GeneralRe: Ummmm... Pin
Ricardo Casquete17-Feb-06 23:30
Ricardo Casquete17-Feb-06 23:30 
QuestionSystem.FlagsAttribute Pin
Stlan17-Feb-06 0:45
Stlan17-Feb-06 0:45 
AnswerRe: System.FlagsAttribute Pin
persée17-Feb-06 2:31
persée17-Feb-06 2:31 
AnswerRe: System.FlagsAttribute Pin
shaul_ahuva17-Feb-06 3:11
shaul_ahuva17-Feb-06 3:11 
AnswerRe: System.FlagsAttribute Pin
PIEBALDconsult16-Jul-09 5:30
mvePIEBALDconsult16-Jul-09 5:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.