Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Key-Value Pairs as Enum-Constants

0.00/5 (No votes)
7 Sep 2008 2  
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.

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.

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:

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.

[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.

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.

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.

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:

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here