摘要:.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. java 调用 .net webservice 示例

    String url="http://IP:端口/LisService.asmx"; String methodName="GetLisResultForBlood&qu ...

  2. Qt 调试时的错误——Debug Assertion Failed!

    在VS2008中写qt程序时调试出现此问题,但在release模式下就不存在,在网上搜罗了一圈,是指针的问题. 问题是这样的: 需要打开两个文件,文件中数据类型是float,我使用QVector进行保 ...

  3. netfilter分析

    转自:http://blog.sina.com.cn/s/blog_a31ff26901013n07.html 一.概述 1. Netfilter/IPTables框架简介 Netfilter/IPT ...

  4. [玩转微信平台]XML的格式化- 如何去掉XML 文档头和命名空间

    前言 系统要求能够回复微信用户发过来的文本消息.实现中使用的实体对象进行XML的序列化的方式来实现XML消息.   微信平台的回复例子 http://mp.weixin.qq.com/wiki/14/ ...

  5. 用户管理 之 Linux 系统中的超级权限的控制

    在Linux操作系统中,root的权限是最高的,也被称为超级权限的拥有者.普通用户无法执行的操作,root用户都能完成,所以也被称之为超级管理用户. 在系统中,每个文件.目录和进程,都归属于某一个用户 ...

  6. 深入剖析 redis 主从复制

    主从概述 redis 支持 master-slave(主从)模式,redis server 可以设置为另一个 redis server 的主机(从机),从机定期从主机拿数据.特殊的,一个 从机同样可以 ...

  7. 【css】a:hover 设置上下边框在 ie6 和 ie7 下失效

    前段时间在写样式的时候发现了这个问题,虽然当时就解决了这个 bug 不过还是记录下,以免再次出现这样的问题. demo 代码: <!doctype html> <html lang= ...

  8. 阿里云 Redis 服务遇到的问题

    ERR unknown command eval 说明: 执行当前 Web 请求期间,出现未经处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息. 异常详细信息: St ...

  9. iOS开发——iOS学习路线

    iOS学习路线 版权声明:欢迎转载,请贴上源地址:http://www.cnblogs.com/iCocos/(iOS梦工厂) 一:自学初步学习路线 二:高级完整学习路线 三:完整知识与能力体系 思维 ...

  10. PInvoke在 2.0 3.0的时候正常 升级到4.0后出错。

    方法1: 设置 CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl,但是我设置了也是出错.换一个con ...