1.认识Enum

  以前一直以为Enum是值类型,在VS中查看Enum的定义时才发现它是一个抽象的类。但是这个类很奇怪,Enum继承了ValueType这个很熟悉的值类型基类,它是唯一一个继承自ValueType类型但又不是值类型的引用类型。Enum还实现了3个接口,分别是IComparable、IFormattable、IConvertible。IComparable中只有一个CompareTo方法用来进行比较,IFormattable中也只有一个方法ToString用来格式化当前枚举对象,IConvertible则是用来进行值类型转化为引用类型的接口。我们自定义的枚举正是继承于Enum类型,之所以要继承Enum,是因为在枚举中不能定义任何属性、方法或事件(其实也就是方法),可是我们还需要操作枚举啊,这时就会用到Enum中的方法。不过又有一个奇怪的事情,在vs中随便写一段枚举如下面代码所示。查看这段代码的IL指令时发现hh的开头部分是.class,我脑子里大概记得枚举是值类型可是在IL中确实显示的是.class。接着我随便写了一个struct放到IL中发现仍然是以.class开头。然后我才发现自己有一个误区,值类型不是struct,struct是属于值类型的。当然最大的疑惑还是.class,从这里也可以看出在.net中所有类型都是class。不要忘了值类型也是继承于ValueType引用类型,到这里问题又来了,值类型是不能继承引用类型的,只能实现接口,那系统内这些值类型继承引用类型到底是如何实现的,特别是内存的分配。

  查阅资料后有一位前辈的意思是系统分配内存时会看这个类型是否继承ValueType,如果继承呢就是值类型,否则就是引用类型。不过刚学习了Enum显然这个观点并不完全对。但是思想可以理解那就是值类型继承引用类型时,值类型会在栈上开辟空间,引用类型会在堆上开辟空间,然后值类型中会有一个指针指向了堆中的引用类型。再回到IL中,我仔细比较了枚举类型、结构体、类这三种类型的IL头部,发现还是有区别的。如下面第二段IL指令所示,它们的区别在于auto与sequential,在.net中有一个内存布局字段LayoutKind,它用来修饰程序中的类型。LayoutKind有三种结果,auto表示内存布局有.net自动分配,sequential表示安照次序相继的分配,explicit我查英文是明确的意思,具体在什么地方用我还不清楚。类和枚举是auto自动分配的,struct和Int32值类型是sequential方式分配的,这个结果显示枚举是引用类型而不是值类型。对这个结果我感到很奇怪,在后面认识枚举中我将写的代码弄得Reflector中发现确实产生了装箱,这说明枚举确实是值类型。这个地方我没搞明白,还请各位前辈指点迷津!

public enum hh
{
a,
b,
c,
} .class public auto ansi sealed hh
extends [mscorlib]System.Enum
{
.field public static literal valuetype Microsoft.hh a = int32() .field public static literal valuetype Microsoft.hh b = int32() .field public static literal valuetype Microsoft.hh c = int32() .field public specialname rtspecialname int32 value__ }
      //枚举
.class public auto ansi sealed hh extends [mscorlib]System.Enum //类
.class public auto ansi beforefieldinit MyClass extends [mscorlib]System.Object //结构体
.class public sequential ansi sealed beforefieldinit jj extends [mscorlib]System.ValueType //Int32
.class public sequential ansi serializable sealed beforefieldinit Int32 extends System.ValueType

2.使用枚举

  回到枚举,枚举默认就是int类型的,它里面只能声明byte,sbyte,short,ushort,int,uint,long ulong这8种类型,在代码里写a='2'是不会报错的,在IL中已经转换为2的asci码50了。关于枚举中的成员赋值,总结起来有3点要注意。第一如果不为枚举成员指定初始值,其将会从0开始自动增加就如上面第一段代码中的枚举hh;第二如果在枚举中为枚举成员指定了初始值,其余剩下的成员将依旧以指定的成员初始值开始依次增加,如下面代码段所示c=6而f=2。第三当在外部写hh h=new hh()时,此时h并不是指第一个枚举值2,而是为0,也就是指向枚举成员中值为0的枚举成员。枚举里面只能声明上面提到的8种整型,因此枚举可以与整型进行相互转换,但是要注意都必须显示转换。如下面第二段代码所示,还有一些关于枚举的简单使用也在其中。最后还有一个关于枚举的功能就是位枚举,其实我们也经常看到。比如一个颜色枚举,有时候我们需要指定多个颜色就像Color.Red|Color.Blue|Color.Green这样。具体代码如下面第三段代码所示,在使用水果枚举时我们可以指定多个值,这给我们带来了不少的好处。只不过判断这种枚举组合是否是一个正确的组合不好判断。

  使用枚举可以让代码变得清晰简单,但是它的功能也可以使用类的静态字段来实现。不过枚举中的值将在编译时即替换为常量,而类的字段则不会,再加上类是分配在堆上的大型资源,性能肯定没有枚举快。同样结构体也可以声明公共字段来完成枚举的功能,那枚举和只含字段的结构体相比哪个更好呢?我觉得还是枚举,因为枚举还有一个优点,前面我特别强调了枚举与整型进行转换时一定要强制转换。这使得强类型的枚举比结构体更加安全,比如有一个方法MyFunc(MyEnum myEnum),参数中指定为枚举类型的话那么传参时将只能传入枚举类型,否则会报错。如果是结构体声明的int类型将有可能使这个方法被传入错误的参数而导致系统不稳定。所以以后对于需要声明分类信息的功能,枚举是首选。我资历浅,如有错误还请各位前辈指出。

public enum hh
{
a=,
b=,
c,
d,
e=,
f,
g,
h
} .class public auto ansi sealed hh
extends [mscorlib]System.Enum
{
.field public static literal valuetype Microsoft.hh a = int32() .field public static literal valuetype Microsoft.hh b = int32() .field public static literal valuetype Microsoft.hh c = int32() .field public static literal valuetype Microsoft.hh d = int32() .field public static literal valuetype Microsoft.hh e = int32() .field public static literal valuetype Microsoft.hh f = int32() .field public static literal valuetype Microsoft.hh g = int32() .field public static literal valuetype Microsoft.hh h = int32() .field public specialname rtspecialname int32 value__ }
static void Main(string[] args)
{
hh h1 = new hh();
Console.WriteLine(h1.ToString());//输出0
hh h2 = hh.a;
Console.WriteLine(h2.ToString());//输出a //枚举与整型相互转换
int i = (int)h2;
hh h3 = (hh);
//也可以使用Enum中的parse方法
hh h4 = (hh)Enum.Parse(typeof(hh), "");
Console.WriteLine(h3.ToString()); //a
Console.WriteLine(h4.ToString()); //24 //枚举与字符串之间的映射,在ToString中传入D表示转换为十进制2,为G表示转换为a
string s1 = h3.ToString("D"); //
string s2 = h3.ToString("G"); //a,ToString默认是以G这种形式转换的。
hh h5 = (hh)Enum.Parse(typeof(hh), "a", false);//h5为a
//在IConvertible中还有许多To类型方法 //arrayValue指的是hh[8],arrayName指的是string[8],它们都按照整型值从小到大排列
Array arrayValue = Enum.GetValues(typeof(hh));
Array arrayName = Enum.GetNames(typeof(hh));
Console.ReadLine();
}
    class Program
{
static void Main(string[] args)
{
//输出Apple,Peach
Fruit f = Fruit.Apple | Fruit.Peach;
Console.WriteLine(f.ToString());
//判断枚举组合是否包含想要的枚举值的2种方式
if (f.ToString().Contains("Apple"))
Console.WriteLine("ok");
if((Fruit.Apple&f)!=)
Console.WriteLine("ok"); //判断枚举中是否有这个成员比如葡萄Grape,可以使用IsDefined,下面的语句将返回false
bool isExist = Enum.IsDefined(typeof(Fruit), "Grape");
//可是对于组合枚举,将无法进行判断,下面两条语句将返回false、true,如果没有Mango将是false
bool isExist2 = Enum.IsDefined(typeof(Fruit), "Apple,Peach");
bool isExist3 = Enum.IsDefined(typeof(Fruit), 0x07);
//而且组合时和的组成可以有多种组成,比如这里的0x07也有可能是0x01与0x06的组合,
//因此对于判断枚举中是否可以存在这个组合枚举无法轻松判断。
Console.ReadLine();
}
}
//Flags特性是专门为枚举而提供的特性,如果没有Flags特性结果将会是7,而不是Apple,Peach
[Flags]
public enum Fruit
{
Watermelon = 0x01,
Pear = 0x02,
Apple = 0x03,
Peach = 0x04,
Mango=0x07
}

声明:本文原创发表于博客园,作者为方小白,如有错误欢迎指出 。本文未经作者许可不许转载,否则视为侵权。

C#基础之枚举的更多相关文章

  1. 【转】Java基础笔记 – 枚举类型的使用介绍和静态导入--不错

    原文网址:http://www.itzhai.com/java-based-notes-introduction-and-use-of-an-enumeration-type-static-impor ...

  2. 黑马程序员:Java基础总结----枚举

    黑马程序员:Java基础总结 枚举   ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 枚举 为什么要有枚举 问题:要定义星期几或性别的变量,该怎么定义?假设用1-7分别 ...

  3. Java基础之枚举类型Enum的使用

    Java基础之枚举类型Enum的使用 定义 public enum AccruedCleanEnum { SPREAD("1","发票"),OTHER(&quo ...

  4. Java基础之枚举

    Java基础之枚举 作为1.5才增加的特性,枚举的使用并不是很多. 枚举其实就是一个比较特殊的类,就如同注解其实也是个特殊的接口一样(注解反编译之后没有了@符号).枚举使用enum关键字声明,通过反编 ...

  5. java基础(十一) 枚举类型

    枚举类型Enum的简介 1.什么是枚举类型 枚举类型: 就是由一组具有名的值的有限集合组成新的类型.(即新的类). 好像还是不懂,别急,咱们先来看一下 为什么要引入枚举类型 在没有引入枚举类型前,当我 ...

  6. C#基础_枚举

    一.在学习枚举之前,首先来听听枚举的优点. 1.枚举能够使代码更加清晰,它允许使用描述性的名称表示整数值. 2.枚举使代码更易于维护,有助于确保给变量指定合法的.期望的值. 3.枚举使代码更易输入. ...

  7. c#编程基础之枚举

    枚举的意义就在于限制变量取值范围. 当可以确定的几种取值时才可以用. 如果输入一个字符串需要进行判断是否是我们需要的字符串时,则一般需要这样写: using System; using System. ...

  8. Java 基础之-枚举

      目录(?)[-] 用法一常量 用法二switch 用法三向枚举中添加新方法 用法四覆盖枚举的方法 用法五实现接口 用法六使用接口组织枚举 用法七关于枚举集合的使用   DK1.5引入了新的类型-- ...

  9. 【Java基础】枚举和注解

    在Java1.5版本中,引入了两个类型:枚举类型enum type和注解类型annotation type. Num1:用enum代替int常量 枚举类型enum type是指由一组固定的常量组成合法 ...

随机推荐

  1. CentOS下搭建SVN服务器

    1.安装SVN SVN数据存储有两种方式,BDB(事务安全表类型)和FSFS(一种不需要数据库的存储系统),为了避免在服务器连接中断时锁住数据,FSFS是一种更安全也更多人使用的方式.SVN的运行方式 ...

  2. WebAPP与原生APP的交互设计区别

    WebAPP和原生APP同为移动端,很少有研究这两项的交互区别,最近公司做了一次从原生APP到WebAPP(HTML5 )的移植,故总结一下期间遇到的问题及不同点总结. 从使用场景上,WebAPP用户 ...

  3. 问题解决——MFC SDI程序 CFormView中控件随窗口缩放

    从来都是做对话框程序,这次想做个SDI的程序,想着用一下带Robbin界面的office2007风格,就不用使用那些花钱的商业控件/UI库了. 如果你不想看我打的文字,可以直接拷走代码,自己声明上定义 ...

  4. C#与MATLAB混合编程

    C#和MatLab的混合编程,充分利用了winform的直观显示和matlab的强大计算能力.在此以一个小例子的形式给大家讲述一下二者混合编程的实现. 一.软件的配置说明 C#版本:VS2010 ma ...

  5. mini2440的SDRAM分析

    首先是2440的存储控制器: 暂时不管是从nand启动还是nor启动,因为我现在只关注内存,从上图可以看到由2440的Memory Controller可以寻址的范围是0x0000,0000---0x ...

  6. kafka basic commands

    kafka-server-start.sh config/server.properties & kafka-server-stop.sh kafka-topics.sh    --creat ...

  7. 【温故而知新-Javascript】使用 Window 对象

    1. 获取 Window 对象 可以用两种方式获得Window对象.正规的HTML5方式是在Document对象上使用defaultView属性.另一种是使用所有浏览器都支持的全局变量window . ...

  8. 矩阵乘法快速幂 codevs 1250 Fibonacci数列

    codevs 1250 Fibonacci数列  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond   题目描述 Description 定义:f0=f1=1 ...

  9. 怎样用ZBrush中复数对象进行工作

    在ZBrush®中有两种方法可以使用复数对象即“多边形组”和“次工具”. 若有疑问可直接访问:http://www.zbrushcn.com/jichu/fushu-duixiang.html 什么是 ...

  10. HDU 2065 “红色病毒”问题 --指数型母函数

    这种有限制的类棋盘着色问题一般可以用指数型母函数来解决,设Hn表示这样的着色数,首先H0=1,则Hn等于四个字母的(A,B,C,D)的多重集合的n排列数,其中每个字母的重数是无穷,且要求A,C出现的次 ...