.NET中的枚举(Enum)
摘要:.NET中的枚举分为简单枚举和标志枚举,这次主要总结一下标志枚举适用条件,以及它的使用方法,并在文章的最后列举枚举使用的一些规范。
在刚接触.NET的枚举时,只用简单的枚举,对于标记枚举,只知道是在枚举类型加上Flags特性,然后给枚举值赋予十六进制的值,并且书中还特别明确规定值必须是以2的指数才可以,这样可以方便在使用时,对多个枚举值进行或运算。随着对.NET的了解不断的深入,现在终于明白了标志枚举的适用场合以及它的使用方法,因此在这里总结一下。
标志枚举的适用条件
在System.Drawing命令空间中有一个FontStyle标志枚举,专门用来设置字体的风格,有Blod、Italic、Regular、Strikeout、Underline这5种风格。当然我们需要设置字体为单个一种风格时,那么FontStyle枚举的用法和简单枚举没什么区别,比如,我们需要把字体风格为设置为粗体,代码如下:
System.Drawing.Font font = new System.Drawing.Font("宋体",12,FontStyle.Bold);
但是,如果我们需要设置字体的风格为粗体的同时还要需要斜体和下划线呢?对于这种情况,简单枚举就不适用了,这就必须使用标志枚举的进行组合才能办到了,代码如下:
System.Drawing.Font font = new System.Drawing.Font("宋体",12, FontStyle.Bold|FontStyle.Italic|FontStyle.Underline);
通过这样的组合就能够达到我们想要的效果。
自定义FontStyle标志枚举,一探究竟
下面我们自己设计一个FontStyle,看看它的内部是如何实现的。代码如下:
[Flags]
public enum FontStyle: byte
{
Bold=0x01,
Italic = 0x02,
Regular = 0x04,
Strikeout=0x08,
Underline=0x10,
}
上面的定义了一个FontStyle枚举,该枚举继承byte类型,通过加上Flags特性,使它成为标志枚举,并且为每一个枚举值赋值一个十六进制的值,每一个值都是2的指数值。下面将详细解释一些为什么要使用2的指数来进行赋值。
为什么使用2的指数值对枚举进行赋值
首先我们要明白,二进制的或运算,或运行无非就4种情况,
0|0=0; 0|1=1; 1|0=1; 1|1=1;
那么二进制10101010和01010101进行或运算就等于11111111,明白了二进制的或运算,再仔细想想,一个字节8位二进制,可以代表0-255。其中1,2,4,8,16,32,64,128是2的指数,分别代表的二进制的00000001,00000010,00000100,00001000,00010000,00100000,01000000,10000000,它们的每个取值刚好是将8位中的某一位设为1。那么这8个值以及它们任意组合(或运算)刚好能够代表$C1_8+C2_8+C3_8+C4_8+C5_8+C6_8+C7_8+C8_8=255 $种情况(其中$C_8^1$是单个枚举,其他都是组合),对标志枚举使用2的指数值进行赋值,能够进行任意的组合,并且任意组合后的值不会有重复。这就是为什么要使用2的指数值对标志枚举进行复制的原因。顺便这里再多说一句,赋值的时候为什么不用10进制,而是用16进制的表示法,前面我们分析了,标志枚举的组合最后都将进行二进制的或运算,而我们在赋值的时候用16进制会更加表现明显,因为每一个16进制的数值,刚好代表二进制4个位,所以两个16进制的数就能代表一个字节,比如0x11,我们化为二进制,只需要对两个1分别换算4个二进制位就行了,1=0001,所以0x11就代表00010001,如果用十进制17来表示,就没那么轻易地看出它的二进制表示。
如何处理组合枚举
当我们把标志枚举赋值为2的指数值之后,我们就可以组合的使用这些枚举值,以期达到我们想要的效果,那么在函数设计中,我们是如何来处理传入进来的枚举组合值呢?其实也非常简单,正是因为他们任意的组合都不会重复,因此每一个数值可以代表其中的一个枚举值或者是一个组合,比如,FontStyle.Bold|FontStyle.Italic|FontStyle.Underline这个组合所代表的数值就位0x01|0x02|0x10=19.
下面设计一个函数处理传入进来的枚举值。代码如下:
static void Test(FontStyle fontStyle)
{
switch ((byte)fontStyle)
{
case 1:
Console.WriteLine("Bold");
break;
case 2:
Console.WriteLine("Italic");
break;
case 3:
Console.WriteLine("Bold&Italic");
break;
case 4:
Console.WriteLine("Regular");
break;
case 6:
Console.WriteLine("Regular&Italic");
break;
case 8:
Console.WriteLine("Strikeout");
break;
case 9:
Console.WriteLine("Strikeout&Bold");
break;
case 10:
Console.WriteLine("Strikeout&Italic");
break;
case 11:
Console.WriteLine("Strikeout&Italic&Bold");
break;
case 16:
Console.WriteLine("Underline");
break;
case 19:
Console.WriteLine("Bold&Italic&Underline");
break;
//else
}
}
因为枚举在CLR内部实现可以看做是数值类型。在Test函数内部我们需要用Switch去判断传入的枚举值,确定是否单个枚举还是组合后的值,并对其做出相应的处理。下面给出测试代码。
static void Main(string[] args)
{
Test(FontStyle.Bold);
Test(FontStyle.Strikeout|FontStyle.Italic);
Test(FontStyle.Bold|FontStyle.Italic|FontStyle.Underline);
Console.ReadKey();
}
测试结果如下:

总结一些设计枚举的规范
- 简单枚举的命名采用单数形式。
- 不要使用Enum、Flag、Flags作为枚举类型的后缀。
- 不要给枚举值的命名加上枚举类型名前缀,比如
FontStyleBlod这样是不规范的。 - 使用枚举代替一些固定的常量集合。
- 使用枚举作为参数、属性、返回值,来保证该API是强类型的API。
- 考虑给枚举提供一个
None=0的枚举值。 - 给标志枚举赋值为2的指数值。
.NET中的枚举(Enum)的更多相关文章
- Java中的枚举Enum
public class TestEnum { /*最普通的枚举*/ public enum ColorSelect { red, green, yellow, blue; } /* 枚举也可以象一般 ...
- C#中的枚举(Enum)你知道多少呢?
写个随笔文章是最难想的,我要是写个C#枚举个人小结,估计博客园的各位园有也觉得是哪个刚接触C#的人写的,要是取个名字叫C#枚举,又觉得不能完全表达自己的意思,现在这个名字看起来还凑合吧,写篇文章不容易 ...
- iOS中的枚举:enum, NS_ENUM, NS_OPTIONS的使用区别
1.enum可以声明一般类型和位掩码(bitmasked)类型 例如: enum Test{// 一般枚举 TestA, TestB, TestC, }; enum{// 匿名枚举 TestA, Te ...
- 关于Java中枚举Enum的深入剖析
在编程语言中我们,都会接触到枚举类型,通常我们进行有穷的列举来实现一些限定.Java也不例外.Java中的枚举类型为Enum,本文将对枚举进行一些比较深入的剖析. 什么是Enum Enum是自Java ...
- C#中的枚举类型(enum type)
ylbtech 原文 C#中的枚举类型(enum type) 概念 枚举类型(enum type)是具有一组命名常量的独特的值类型.在以下示例中: enum Color { Red, Green, B ...
- C# 中的枚举类型 enum (属于值类型)
原文 C# 中的枚举类型 enum (属于值类型) C# 支持两种特殊的值类型:枚举和结构. 声明枚举:声明时要声明所有可能的值. using System; using System.Collect ...
- Android中是否推荐使用枚举Enum
一.Enum的产生 Java1.5中引入了枚举的语法,包括Enum,EnumSet,EnumMap等.其中Enum就是我们在C或C++中见过的枚举类型,但是Java中的枚举又比C或C++中的枚举更成熟 ...
- Mybatis中使用自定义的类型处理器处理枚举enum类型
知识点:在使用Mybatis的框架中,使用自定义的类型处理器处理枚举enum类型 应用:利用枚举类,处理字段有限,可以用状态码,代替的字段,本实例,给员工状态字段设置了一个枚举类 状态码,直接赋值给对 ...
- Lua 与C/C++ 交互系列:注冊枚举enum到Lua Code中
在Lua Code中注冊C/C++的枚举很easy,就像注冊全局变量一样.我们使用枚举名称作为命名空间,来避免注冊的枚举发生冲突.注冊的枚举存储在全局环境(线程环境)中. 当在Lua Code中訪问枚 ...
随机推荐
- mysql中You can’t specify target table for update in FROM clause错误解决方法
mysql中You can't specify target table for update in FROM clause错误的意思是说,不能先select出同一表中的某些值,再update这个表( ...
- Undokumentierte @Formeln/LotusScript im Lotus Notes Client/Server
Erstellung von Replik-IDs mittels @Text-Funktion@Text( @Now; "*" )Source NoPersist option ...
- Python中使用自定义类class作为海量数据结构时内存占用巨大的问题
最近碰到处理一个二十多兆的文件时内存蹭蹭的吃掉四百多兆,吓死宝宝了. 无奈毕竟接触python时间有限,还没有完整的看过python的一些基础知识,我想一个合格的pythoner应该不会碰到这个问题. ...
- android自定义seekBar
Android原生控件只有横向进度条一种,而且没法变换样式,比如原生rom的样子 很丑是吧,当伟大的产品设计要求更换前背景,甚至纵向,甚至圆弧状的,咋办,比如 ok,我们开始吧: 一)变换前背景 先来 ...
- HDU 3874 Necklace (树状数组 | 线段树 的离线处理)
Necklace Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total S ...
- WPF 获取程序路径的一些方法,根据程序路径获取程序集信息
一.WPF 获取程序路径的一些方法方式一 应用程序域 //获取基目录即当前工作目录 string str_1 = System.AppDomain.CurrentDomain.BaseDirector ...
- WPF中System.Diagnostics.Process.Start的妙用
我们经常会遇到在Winform或是WPF中点击链接或按钮打开某个指定的网址, 或者是需要打开电脑中某个指定的硬盘分区及文件夹, 甚至是"控制面板"相关的东西, 那么如何做呢? 答案 ...
- LoadRunner场景参数文件部分参数说明(我在某银行的整理)
由于场景中脚本繁多,同时设置60个脚本的“运行时设置”会提示个数限制信息,这时可以考虑通过场景的参数文件配置来批量解决这些事情,主要是提高工作效率. 选中自己保存的controller场景,鼠标右键点 ...
- exerunexplorer.exe
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...
- is running beyond physical memory limits. Current usage: 2.0 GB of 2 GB physical memory used; 2.6 GB of 40 GB virtual memory used
昨天使用hadoop跑五一的数据,发现报错: Container [pid=,containerID=container_1453101066555_4130018_01_000067] GB phy ...