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 7 无GUI静默安装 oracle 12c,打造轻量linux化服务器

    CentOS 7 下载地址:http://mirrors.opencas.cn/centos/7/isos/x86_64/CentOS-7-x86_64-Everything-1511.iso 一.安 ...

  2. HDU 4045 Machine scheduling (组合数学-斯特林数,组合数学-排列组合)

    Machine scheduling Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  3. sql 把特定数据排在最前面

    感谢www.baidu.com/p/dongfanghong_1 sql大神,简单的语法运用起来简直活了. 第一法] select * from table where name='D' UNION ...

  4. hdu 2255 奔小康赚大钱--KM算法模板

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 题意:有N个人跟N个房子,每个人跟房子都有一定的距离,现在要让这N个人全部回到N个房子里面去,要 ...

  5. URAL 1430 Crime and Punishment

    Crime and Punishment Time Limit:500MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u ...

  6. Swift 学习笔记 enum 枚举类型

    异端,异端啊,我感觉这是map吧? enum ATMStatus { case Success(Int) case Error(String) } func withdraw(amount: Int) ...

  7. 【iOS 初见】第一个简单的 iOS 应用

    本实例来自 <iOS编程(第4版)>,介绍如何编写一个简单的 iOS 应用. 功能为:在视图中显示一个问题,用户点击视图下方的按钮,可以显示相应的答案,用户点击上方的按钮,则会显示一个新的 ...

  8. 写一个iOS VoIP应用需要知道什么?

    IOS编程--VoIP解密 一般来说, IOS很少给App后台运行的权限. 仅有的方式就是 VoIP. IOS少有的为VoIP应用提供了后台socket连接,定期唤醒并且随开机启动的权限.而这些就是I ...

  9. Java虚拟机详解03----常用JVM配置参数

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  10. 开坑,Unix环境高级编程,转行之路又得缓缓了

    不要问我基础,我用了近6年的Linux系统,最早的版本可以追溯到Ubuntu 8.04,常用的命令 VIM基本上是没压力,遇到问题google 配置环境变量 网络环境也不在话下, C语法基本熟练,过去 ...