Click here to Skip to main content
11,922,641 members (55,327 online)
Click here to Skip to main content
Add your own
alternative version


11 bookmarked

Using a Generic Type to Simplify Flags Enumeration Operations

, 6 Dec 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
Using a generic type taking an enumerated type to provide simple manipulation of the enumeration as an alternative to [Flags] attribute


The introduction of the [Flags] attribute made it very much easier to set up and use flag registers based on enumerated types. However, there are times when it can be cumbersome to query the state of individual flags or combinations of flags resulting in code that is difficult to understand without careful reading.

By providing a generic type that allows any enumeration, whether marked with the [Flags] attribute or not, to be used as a flag type with methods to clear, set and interrogate flag state, we can make it easier to use such types and make the code easier to understand and therefore easier to develop and maintain.

Because we can use enumerations not marked with the [Flags] attribute, we can use enumerations in third party DLLs, assuming it is appropriate and necessary, without having to wrap them in a marked in-house enumeration.

Using the Code


The developer defines an enumeration to meet the application's requirements. He or she then creates an instance of the generic type Register<Enumeration> with the desired enumerated type and uses that in place of a variable of the enumerated type.

Class : Register<Enumeration>

Constructor Comment
Register<T>() Creates an instance based on enumerated type T with all flags cleared.
Register<T>(T) Creates an instance based on enumerated type T with the specified flags set and the remainder clear. Use logical OR to set multiple flags.

Method Returns Comment
Set() T Sets all flags in the register. Returns the updated state of the register.
Set(T) T Set the specified flags. Use logical OR to set multiple flags. Returns the updated state of the register.
Clear() T Clears all flags in the register. Returns the updated state of the register.
Clear(T) T Clear the specified flags. Use logical OR to set multiple flags. Returns the updated state of the register.
IsSet(T) bool Query the state of a flag in the register. Multiple flags can be queried Using logical OR. Returns false if one or more of the queried flags is clear.

Property Type Comment
State T Returns the current state of the register as the instantiating enumerated type.

Using : Register<Enumeration>


Define our enumeration. Note that we no longer need to mark this with the [Flags] attribute.

public enum Greek
    Alpha   = 1,
    Beta    = 2,
    Gamma   = 4,
    Delta   = 8,
    Epsilon = 16,

Now create an instance of the Register using the appropriate enumeration:

// We can either create an instance with all flags clear...
Register<Greek> startClear = new Register<Greek>();
// ... or create a flag register with one or more flags set.
Register<Greek> startSet = new Register<Greek>(Greek.Delta | Greek.Gamma);

And use it as needed:

// Set all flags in a single operation
// Clear flags either singly or in combination.
// Set flags either singly or in combination.
// Querying the state of an individual flag
Console.WriteLine("{0} set {1}", Greek.Alpha, startClear.IsSet(Greek.Alpha));
// Querying multiple flags in one operation.
Register<greek> startSet = new Register<greek>(Greek.Delta | Greek.Gamma);
Console.WriteLine("{0} set {1}",
	Greek.Alpha.ToString() + Greek.Delta.ToString(),
	startSet.IsSet(Greek.Alpha|Greek.Delta));	// Alpha flag is clear 
						// so returns false.
Console.WriteLine("{0} set {1}",
	Greek.Gamma.ToString() + Greek.Delta.ToString(),
	startSet.IsSet(Greek.Gamma|Greek.Delta)); 	// Both flags set returns true

We can also see that we have type safety if we try and assign the state of our Register<T> instance to another enumerated type.

Greek g  = startClear.State;   // All hunky dory.
Island i = startClear.State;   // Compile time error.


Internally the enumeration is held as int32. This reduces the amount of casting required to persuade the compiler that type <T> allows bitwise operations. We cast back to <T> only if a return value is required.

For most cases where a flag register is required, int32 is probably overkill, but because we control the internal representation of the register, we could implement it any way we chose.

It would have been nice to be able to constrain the type parameter <T> to allow the use of only enumerated types, e.g. class Y<T> where T : enum unfortunately no such constraint exists. This means that a developer could instantiate a Register<T> with pretty much any type so running the risk of a runtime error. The following will, alas, compile...

Register<string> r = new Register<string>(); have been warned.


Decades as a software developer creating and maintaining applications have made me appreciate anything, even something as trivial as reducing the effort required to manipulate bit flags, that makes it easier for me to write code that is correct the first time around and also allows anyone who inherits responsibility for the code to easily understand what I was trying to do when (inevitably) the business rules change and the code has to be revised in short order and with no access to the original design documentation.


You might also like to have a look at an earlier article that covers the same ground and provides a workaround for constraint problem : EnumOperators


  • November 2010 - Convert type specific 1.1 code to type generic 3.5 code
  • November 2010 - Add link to PIEBALDConsults article.


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


About the Author

United Kingdom United Kingdom
Nothing interesting to report.

You may also be interested in...

Comments and Discussions

GeneralMy vote of 1 Pin
AndyHo6-Dec-10 2:04
memberAndyHo6-Dec-10 2:04 
GeneralRe: My vote of 1 Pin
cigwork6-Dec-10 3:10
membercigwork6-Dec-10 3:10 
GeneralRe: My vote of 1 [modified] Pin
AndyHo6-Dec-10 3:18
memberAndyHo6-Dec-10 3:18 
GeneralRe: My vote of 1 Pin
PIEBALDconsult6-Dec-10 8:10
mvpPIEBALDconsult6-Dec-10 8:10 
GeneralRe: My vote of 1 Pin
Philip Liebscher13-Dec-10 13:38
memberPhilip Liebscher13-Dec-10 13:38 
While your comments may be true, the effort in writing, what I thought was a well written article is worth more than a vote of 1.
GeneralRe: My vote of 1 Pin
cigwork6-Dec-10 3:50
membercigwork6-Dec-10 3:50 
RantRe: My vote of 1 Pin
Pete Goodsall7-Dec-10 3:14
memberPete Goodsall7-Dec-10 3:14 
Generalif you use a underlying type of long, ulong the system fails! Pin
AndyHo6-Dec-10 2:03
memberAndyHo6-Dec-10 2:03 
GeneralRe: if you use a underlying type of long, ulong the system fails! Pin
cigwork6-Dec-10 3:07
membercigwork6-Dec-10 3:07 
GeneralIn .NET 4.0 there is a HasFlag that helps a lot Pin
Sacha Barber3-Dec-10 22:39
mvpSacha Barber3-Dec-10 22:39 
GeneralRe: In .NET 4.0 there is a HasFlag that helps a lot Pin
cigwork4-Dec-10 1:05
membercigwork4-Dec-10 1:05 
GeneralRe: In .NET 4.0 there is a HasFlag that helps a lot Pin
Sacha Barber4-Dec-10 21:26
mvpSacha Barber4-Dec-10 21:26 
GeneralThoughts Pin
PIEBALDconsult3-Dec-10 12:09
mvpPIEBALDconsult3-Dec-10 12:09 
GeneralRe: Thoughts Pin
cigwork4-Dec-10 1:08
membercigwork4-Dec-10 1:08 
GeneralMy vote of 5 Pin
burak2993-Dec-10 11:31
memberburak2993-Dec-10 11:31 
GeneralThank you! Pin
Toli Cuturicu3-Dec-10 11:29
memberToli Cuturicu3-Dec-10 11:29 

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.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.151125.1 | Last Updated 6 Dec 2010
Article Copyright 2010 by cigwork
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid