摘要:.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)的更多相关文章

  1. Java中的枚举Enum

    public class TestEnum { /*最普通的枚举*/ public enum ColorSelect { red, green, yellow, blue; } /* 枚举也可以象一般 ...

  2. C#中的枚举(Enum)你知道多少呢?

    写个随笔文章是最难想的,我要是写个C#枚举个人小结,估计博客园的各位园有也觉得是哪个刚接触C#的人写的,要是取个名字叫C#枚举,又觉得不能完全表达自己的意思,现在这个名字看起来还凑合吧,写篇文章不容易 ...

  3. iOS中的枚举:enum, NS_ENUM, NS_OPTIONS的使用区别

    1.enum可以声明一般类型和位掩码(bitmasked)类型 例如: enum Test{// 一般枚举 TestA, TestB, TestC, }; enum{// 匿名枚举 TestA, Te ...

  4. 关于Java中枚举Enum的深入剖析

    在编程语言中我们,都会接触到枚举类型,通常我们进行有穷的列举来实现一些限定.Java也不例外.Java中的枚举类型为Enum,本文将对枚举进行一些比较深入的剖析. 什么是Enum Enum是自Java ...

  5. C#中的枚举类型(enum type)

    ylbtech 原文 C#中的枚举类型(enum type) 概念 枚举类型(enum type)是具有一组命名常量的独特的值类型.在以下示例中: enum Color { Red, Green, B ...

  6. C# 中的枚举类型 enum (属于值类型)

    原文 C# 中的枚举类型 enum (属于值类型) C# 支持两种特殊的值类型:枚举和结构. 声明枚举:声明时要声明所有可能的值. using System; using System.Collect ...

  7. Android中是否推荐使用枚举Enum

    一.Enum的产生 Java1.5中引入了枚举的语法,包括Enum,EnumSet,EnumMap等.其中Enum就是我们在C或C++中见过的枚举类型,但是Java中的枚举又比C或C++中的枚举更成熟 ...

  8. Mybatis中使用自定义的类型处理器处理枚举enum类型

    知识点:在使用Mybatis的框架中,使用自定义的类型处理器处理枚举enum类型 应用:利用枚举类,处理字段有限,可以用状态码,代替的字段,本实例,给员工状态字段设置了一个枚举类 状态码,直接赋值给对 ...

  9. Lua 与C/C++ 交互系列:注冊枚举enum到Lua Code中

    在Lua Code中注冊C/C++的枚举很easy,就像注冊全局变量一样.我们使用枚举名称作为命名空间,来避免注冊的枚举发生冲突.注冊的枚举存储在全局环境(线程环境)中. 当在Lua Code中訪问枚 ...

随机推荐

  1. CoreOS实践(2)—在coreos上安装Kubernetes

    下载kubernetes sudo mkdir -p /opt/bin sudo wget https://storage.googleapis.com/kubernetes/binaries.tar ...

  2. Apex Design Patterns

    Apex allows you to build just about any custom solution on the Force.com platform. But what are the ...

  3. arulesSequences包做序列模式的关联分析

    实验数据: 实验文件: ? 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 02 ...

  4. 机器学习编程语言之争,Python 夺魁【转载+整理】

    原文地址 en cn 本文内容 表现平平的 MATLAB 貌似强大的 Julia 本身无错的 R 语言 逐渐没落的 Perl 老而弥坚的 Python 我个人很喜欢 Python~ 随着科技的发展,拥 ...

  5. 定时从远程的数据库中取数据,然后把取出来的数据插入或更新本地的oracle数据库的表

    最近项目中有一种需求: 大致需求是这样的 通过给定的 用户名和密码 要定时从远程的数据库中取数据,然后把取出来的数据插入或更新本地的oracle数据库的表 项目的结构式struts1 hibernat ...

  6. Java 反射练习

    已同步更新至个人blog:http://dxjia.cn/2015/08/java-reflect/ 引用baidubaike上对JAVA反射的说明,如下:JAVA反射机制是在运行状态中,对于任意一个 ...

  7. IOS从一个APP跳到另一个APP

    以下为跳转到大众点评APP代码如下: NSString *requestUrlString = @"dianping://shopinfo?id=1000"; NSURL *req ...

  8. C#后台弹出对话框

    Page.ClientScript.RegisterStartupScript(this.GetType(), "", "<script language='jav ...

  9. 使用SQL Server 2014 In-Memory 内存数据库时需要注意的地方

    转载: http://www.infoq.com/cn/articles/sql-server-2014-memory-database http://www.cnblogs.com/Amaranth ...

  10. ORACLE自定义顺序排序-转

    ORACLE可以借助DECODE函数,自定义顺序排序: select * from ( select 'Nick' as item from dual union all select 'Viki' ...