枚举常量作为键值对






4.33/5 (7投票s)
一个类似枚举的类,支持标志(最多 8192 个),具有附加的值类型数据、描述和 FastSerializer 支持。
引言
在我们最新的 WCF 项目中,我们需要将一些枚举值打包到消息头中 (BitFlags
)。此外,我经常需要包含枚举键及其值的键值对。 大多数情况下,这些用于域内的动态设置,但有时,它们需要通过服务发送到服务器(序列化)。所以我想要有常量,因为枚举上的属性不能让我满意。除此之外,BitFlags
应该更具可扩展性,至少是 1024 或更多。序列化应该适合我根据 CP 上精彩文章构建的 FastSerializer
。
非常重要,如果您不需要键值对,或者至少不需要高达 8192 的 BitFlags
,那么本文不适合您。 但也许,您是真正的专家,可以帮助我改进类设计(见下文)。 干杯!
背景
我建议阅读这些很棒的文章,我从中受益匪浅,并在我的示例代码中使用了一些部分
使用代码
代码的使用可能比代码本身更简洁。 由于隐式运算符,可以通过使用字符串、常量或十进制值来以任何方式设置初始键值。
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;
主要为了 UI 支持,可以全部设置或反转标志,或者我们可以从常量、键、值、名称(键的名称)或描述中获取列表。 该列表包含当前实例中的所有位或已使用的位。
this.myColor.Invert();
this.myColor.MarkAll();
EColor[] items = this.myColor.ListConst; // all
EColor[] items = this.myColor.ListFlagged; // used bits
最有用的还是序列化功能以及提供的值
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
设置类
首先,需要使用 EFlags
属性标记 EnumConstant
类,该属性描述类包含多少个枚举键(=BitFlags
)。 在内部,bool[]
数组保存设置的位。 该类派生自 EnumBase<TC, TT>
,其中 TC
是派生的类,而 TT
是值包含的类型; 例如,在示例中,EColor
被定义为 Color
类型的枚举。
[Serializable]
[EFlags(EFlagSize.b32)]
public class EColor : EnumBase<EColor, Color>
其次,需要声明所有构造函数,调用基构造函数。 这样做的原因是运算符(下一步)。 大多数构造函数需要是 private
,因为我们有由常量管理的 BitFlags
。 因此,实例的初始化通常通过常量赋值来完成。
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) {}
第三,需要声明所有运算符。 似乎来自基类的运算符不能在派生类中使用。 可能是因为用于描述实例标识的常量。 我没有设法让它们在基类中。
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 ...
最后,需要声明所有常量,此外,我们还有一个封闭的枚举,可以帮助我们用更少的文本来完成此操作。 此外,如果枚举是 public
,我们可以使用封闭的枚举来进行属性和切换。 就我个人而言,我声明枚举为 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 );
不是纯粹的哲学,但方便吗?
当然,并非每个人都认为做这么多工作来获得作为键值常量的枚举是有趣或有用的。 这样的类是一个完整的缓存,具有一些特定的功能,但易于挂钩到业务对象并序列化以供其他地方使用。 代码肯定会变得非常可读
if (this.myColor.Contains(EColor.eBackground))
{
control.Background = this.myColor.EnumValue;
}
如果有人能告诉我如何拥有一个执行相同操作(运算符/构造函数)的基类,而无需在派生类中声明它们,我将很高兴听到。 谢谢。