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

Key-Value Pairs as Enum-Constants

Rate me:
Please Sign up or sign in to vote.
4.33/5 (7 votes)
7 Sep 2008CPOL3 min read 61.8K   213   19   5
An enum-like class that supports flags (up to 8192), has additional value-type data, description, and FastSerializer support.

Introduction

In our newest WCF project, we needed to pack some enum-values in a message header (BitFlags). Also, I frequently had key-value pairs containing an enum-key with a value. Mostly, these were used for dynamic settings within the domain, but sometimes, they needed to be send to the server by the service (serializing). So I wanted to have constants, since attributes on enums did not satisfy me. In addition to this, the BitFlags should be more scalable, at least 1024 or better more. The serialization should fit it the FastSerializer I built according to the great articles here on CP.

Very important, if you do not need a key-value pair, or at least the BitFlags up to 8192, this article is not intended for you. But maybe, you are the real crack that can help me with a better class design (see below). Cheers!

EnumConstantsHints.png

Background

I recommend reading these great articles which I profited a lot from and used parts in my sample code:

Using the code

The usage of the code is probably neater than the code itself. Because of the implicit operators, the initial Key-Value can be set anyhow, by using strings, constants, or decimal values.

C#
this.myColor = 'BackGround';
this.myColor = '1'; // = EColor.eBackGround
this.myColor = 1;   // = EColor.eBackGround
this.myColor = EColor.eBackGround

this.myColor = EColor.eBackGround+EColor.eInnerBorder;
this.myColor += EColor.eForeGround;
this.myColor += 2; // = EColor.eForeGround;

Mainly for UI-Support, the flags can be set all or inverted, or we can get a list from the constants, keys, values, names (of key), or a description. The list contains either all or the used bits in the current instance.

C#
this.myColor.Invert();
this.myColor.MarkAll();
 
EColor[] items = this.myColor.ListConst;    // all 
EColor[] items = this.myColor.ListFlagged;    // used bits

Most useful is the serialization-capabilities as well as the provided values:

C#
byte[] rawData  = this.myColor; 
this.otherColor = rawData;

bool[] bitFlags = this.myColor; 
this.otherColor = bitFlags;

Int32  decimal   = this.myColor.DecValue;
Color  anytype   = this.myColor.EnumValue; // only for single value
string constName = this.myColor.ConstName; // use List for bitFlags

Setup the class

First an EnumConstant class needs to be marked with the EFlags attribute that describes how many enum-keys the class contains (=BitFlags). Internally, a bool[] array holds the set bits. The class is derived from EnumBase<TC, TT>, where TC is the class deriving and TT the type that the value is containing; e.g., in the sample, EColor is defined to be enums of type Color.

C#
[Serializable]
[EFlags(EFlagSize.b32)]
public class EColor : EnumBase<EColor, Color>

Second, all constructors need to be declared, calling the base-constructors. The reason for this is the operators (next step). Most of the constructors need to be private, since we have the BitFlags managed by the constants. Therefore, the initialization of an instance is normally done by the assignment of a constant.

C#
internal EColor() : base() { }

private  EColor(E decValue, Color eValue) 
    : base((Int32)decValue, eValue, typeof(E), String.Empty) {}

public   EColor(SerializationInfo info, StreamingContext context) 
    : base(info, context) {}

private  EColor(Int32 decValue )  : base(decValue) {}
private  EColor(Color eValue )    : base(eValue)   {}
private  EColor(string eName )    : base(eName)    {}
private  EColor(byte[] rawValue ) : base(rawValue) {}
private  EColor(bool[] bitFlags ) : base(bitFlags) {}

private  EColor(bool addFlags, object value1, 
                object value2) : base(addFlags, value1, value2) {}

Third, all operators need to be declared as well. It seems that operators from the base-class cannot be used in derived classes. Probably because of the constants that are used to describe the identity of an instance. I did not manage to have them in the base-class.

C#
public static implicit operator EColor(Int32 operatorValue) 
{ 
   return new EColor(operatorValue); 
}
// more ...
public static EColor operator + (EColor value1, EColor value2) 
{ 
   return new EColor(true, value1.CmpValue, value2 .CmpValue); 
}
// more ...
public static EColor operator - (EColor value1, EColor value2) 
{ 
  return new EColor(false, value1.CmpValue, value2 .CmpValue); 
}
// more ...

Finally, all constants need to be declared, and in addition, we also have an enclosed enum inside that helps us to have this done with less text. Also, if the enum is public, we can use the enclosed enum for attributes and switches. Personally, I declare the enum internal.

C#
public enum E
{
   None         = 0,
   BackGround   = 1,
   ForeGround   = 2,
   InnerBorder  = 3,
   OuterBorder  = 4,
   TextNormal   = 5,
   TextHighlite = 6,
}

public static readonly EColor eNone         = new EColor(E.None, 
                                              Color.Empty      );
public static readonly EColor eBackGround   = new EColor(E.BackGround, 
                                              Color.AliceBlue, 'use Background Color' );
public static readonly EColor eForeGround   = new EColor(E.ForeGround, 
                                              Color.Bisque,    'use Foreground Color' );
public static readonly EColor eInnerBorder  = new EColor(E.InnerBorder,  Color.DodgerBlue );
public static readonly EColor eOuterBorder  = new EColor(E.OuterBorder,  Color.Tomato     );
public static readonly EColor eTextNormal   = new EColor(E.TextNormal,   Color.Yellow     );
public static readonly EColor eTextHighlite = new EColor(E.TextHighlite, Color.RosyBrown  );

Not pure philosophy, but handy?

Surely, not everyone thinks that it is fun or useful to do such an amount of work to get an enum as a key-value constant. Classes like this are a full cache with some specific functionality, but easy to hook in an Business Object and serialized to be used elsewhere. The code surely becomes very readable:

C#
if (this.myColor.Contains(EColor.eBackground))
{
   control.Background = this.myColor.EnumValue;
}

If someone can tell me how to have a base class that does the same (operators/constructors) without having them declared in the derived class, I will be happy to hear. Thanks.

License

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


Written By
Software Developer
Switzerland Switzerland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralCtrl+Space Pin
Ennis Ray Lynch, Jr.8-Sep-08 10:49
Ennis Ray Lynch, Jr.8-Sep-08 10:49 
GeneralRe: Ctrl+Space Pin
christoph brändle8-Sep-08 20:22
christoph brändle8-Sep-08 20:22 
thanks, Ctrl+Space, you should write an article about it, mmh Poke tongue | ;-P
GeneralI probably should Pin
Ennis Ray Lynch, Jr.9-Sep-08 8:56
Ennis Ray Lynch, Jr.9-Sep-08 8:56 

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.