摘要:.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. mybatis中传入String类型参数异常

    在使用mybatis时,写了一条sql语句,只有一个String类型的参数, 示例代码 <select id="getApplyNum" parameterType=&quo ...

  2. [转]Java Spring的Ioc控制反转Java反射原理

    转自:http://www.kokojia.com/article/12598.html 学习一个东西的时候,如果想弄明白,最好想想框架内部是如何实现的,如果是我做我会怎么实现.下面我就写一个Ioc ...

  3. Oracle中Kill session的研究(转 出自eagle)

    itpub link: http://www.itpub.net/235873.html 我们知道,在Oracle数据库中,可以通过kill session的方式来终止一个进程,其基本语法结构为: a ...

  4. c10k问题及其解决方案

    本文主要讲述高并发http应用中的c10k瓶颈问题:在很多服务器初始状态下,无法服务1w左右的并发连接.这与每次服务的资源消耗.服务器的硬件配置固然有关,但很多时候是被linux的默认配置以及软件st ...

  5. Android Dagger依赖注入框架浅析

    今天接触了Dagger这套android的依赖注入框架(DI框架).感觉跟Spring 的IOC差点儿相同吧.这个框架它的优点是它没有採用反射技术(Spring是用反射的),而是用预编译技术.因为基于 ...

  6. 绘制n边形:用两个以上的控件来控制矩形的颜色、大小、位置及空实心(程序代写)

    绘制n边形:用两个以上的控件来控制矩形的颜色.大小.位置及空实心.(n由键盘输入) package lzy.di9zhang; import java.awt.BorderLayout;import ...

  7. Flash Builder中“Error: #2036 加载未完成”错误的解决方法

    复制了一个名称为A的widget包,重命名为B,包含B.mxml和B.xml(配置文件),编译后无法加载B包创建的widget,报错为: 解决办法: 1.在工程的根目录下找到.actionScript ...

  8. 从Tmux 转到GNU Screen

    网上很多地方都说Tmux比GNU Screen要好用,不过无意间看到这篇Switching from tmux to GNU Screen之后,我发现GNU Screen的窗口/区域概念更好,至少是更 ...

  9. [Javascript] Functor Basic Intro

    Well, this stuff will be a little bit strange if you deal with it first time. Container Object: Just ...

  10. VS2013 解决方案文件结构分析

    http://www.cnblogs.com/haogj/p/4248030.html Visual Studio 的解决方案文件是一个文本文件,其中的内容不是太复杂,有些时候 Visual Stud ...