大家在学习DateTime的时候有没有发现一个DayOfWeek类型,示意星期几。应用F12就能够看到它的定义:

这里就呈现了:

枚举(Enum)

枚举(enum)是和类(class)、构造(struct)并列的一种类型。它的成员又被称之为枚举值,枚举值不能有任何修饰符,只能蕴含两局部:

  • 名称,比方DayOfWeek中的Sunday、Monday等,名称个别是“有意义的”,以不便开发人员调用
  • 底层数据,比方DayOfWork中的0、1、2等。默认底层数据是int类型,还能够应用其余整数类型,比方byte、short等,如下所示:

    enum Grade : short //默认是int类型,当初是short类型 { }

底层数据也能够不写,不写的话默认从0开始,从上到下顺次减少1:

enum Grade : short //默认是int类型 { Excellent, //不写底层数据默认为O Passed, //默认以1的步长递增底层数据 Failed = 8 //指定底层数据 }

枚举能够像类型一样应用:

//申明Grade属性 public Grade grade { get; set; } //作为办法的返回值 static Grade GetBy(int score){} //作为办法的参数 static int GetBy(Grade score){}

它的值间接枚举名点(.)出即可:

//申明变量/字段 Grade grade = Grade.Excellent;

因为枚举的整型底层数据,所以能够在枚举和整型之间进行强制转换:

Console.WriteLine((short)Grade.Excellent); //int类型也行(能够和short转换) Console.WriteLine((int)Grade.Passed); Console.WriteLine((int)Grade.Failed); Console.WriteLine((Grade)0); //Excellent Console.WriteLine((Grade)16); //无奈转换时也不会报错,间接输入16

留神:枚举的默认值是:

  • 0所对应的枚举值,或者
  • 如果找不到0所对应的枚举值,就间接为0

演示:

为什么要应用枚举呢?

以DayOfWork为例,如果没有枚举,咱们如何传递“星期几”呢?比方咱们有一个办法,能够依据星期几返回bool值,如果是星期三和星期六,就返回true,示意当天不上课,^_^

怎么申明这个办法呢?参数用什么类型?int,string?比方这样:

static bool IsRest(int dayofWork) { return dayofWork == 3 || dayofWork == 6; }

这样写,有两个问题:

  1. 开发人员怎么晓得3代表星期三,6代表星期六?你说这个还能够对应着来,星期天你怎么示意?0,还是7?不同的文化可能有不同的定义,这就是问题。
  2. 有没有可能传入一个参数:8?因为int类型的取值是没有限度的。

@想一想@:如果用string类型呢?

所以咱们用DayOfWork的枚举来做:

static bool IsRest(DayOfWeek dayofWork) { return dayofWork == DayOfWeek.Wednesday || dayofWork == DayOfWeek.Saturday; }

首先,DayOfWeek.Wednesday表义十分分明;而后,参数是枚举类型,所以你没方法传入一个不存在的枚举值的。这些,都极大的进步了代码的可读性和健壮性(少bug)。

枚举通常和

switch...case

配合应用,比方:

Grade grade = Grade.Excellent; switch (grade) { case Grade.Excellent: Console.WriteLine("发10个红包"); break; case Grade.Passed: Console.WriteLine("发5个红包"); break; case Grade.Failed: Console.WriteLine("没有红包了"); break; default: Console.WriteLine("怎么回事?"); break; }

整段代码的意思就是,依据grade的值进行分支:

  1. 如果grade的值等于Grade.Excellent,输入"发10个红包";
  2. 如果grade的值等于Grade.Passed,输入"发5个红包";
  3. 如果grade的值等于Grade.Failed,输入"没有红包了";
  4. 如果grade的值不等于下面的任何的一个枚举值,输入"怎么回事?"

这种逻辑其实用if...else...也能够实现,然而switch...case看起来更整洁一些。但要留神以下几点:

  • 只能进行“等值”运算,也就是说只能判断switch()中的值是否等于case前面的值,不能进行大于小于等其余运算。
  • 代码执行时从上往下比拟,所以程序很重要。尤其是default,相当于if...else...中最初兜底的else,应该是在上述所有case条件都不满足的状况下才执行的,所以只能放在最初。同时强烈建议总是带上default,哪怕用于报异样!
  • 不要遗记break,break意味着跳出switch域。如果两个case之间没有break只有业务逻辑语句,就会报编译谬误;如果两(多)个case之间没有任何其余语句,这些case条件形成一种“或”的关系,比方下面周三周六劳动的需要咱们就能够这样实现:

    static bool IsRest(DayOfWeek dayofWork) { switch (dayofWork) { case DayOfWeek.Saturday: case DayOfWeek.Thursday: return true; //此处能够用return代替break default: return false; } }

因为枚举的底层数据是整数类型,它还能够进行

位运算

首先要把传入的数转化成二进制,而后按二进制对齐,对每一个雷同的位的值进行相应运算——这就被称之为位运算。

咱们这里介绍三种位运算:

  • &:读作“位与”,只有两个1才为1
  • |:读作“位或”,只有一个1就为1
  • ^:读作“异或”,两个值雷同才为1

    Console.WriteLine(1 | 2); // 01 | 10 => 11 (3) Console.WriteLine(2 | 4); // 010 | 100 => 110 (6) Console.WriteLine(1 & 2); // 01 & 10 => 00 (0) Console.WriteLine(2 & 4); // 010 & 100 => 000 (0) Console.WriteLine(1 ^ 2); // 01 ^ 10 => 11 (3) Console.WriteLine(2 ^ 4); // 010 ^ 100 => 110 (6)

(除|和&以外,还有><等位移运算、补位运算,我的项目开发中用得非常少,这里不予讲述)

常见面试题:|和||,&和&&的区别

当|和&利用于逻辑运算时,失去的后果同||和&&是统一的。然而后者是有短路操作进行优化的。具体来说,是指:在组合逻辑运算中,一旦可能失去最终后果,就立刻终止运算,间接返回后果。比方:

  • 在逻辑或运算中,只有有一个条件为真,整个运算后果必然为真;
  • 在逻辑且运算中,只有有一个条件为假,整个运算后果必然为假,

就不必再计算前面的条件了。

static bool condition1() { Console.WriteLine("condition1()..."); return true; //或者 false } static bool condition2() { Console.WriteLine("condition2()..."); return false; //或者 true } Console.WriteLine(condition1() | condition2()); Console.WriteLine(condition1() || condition2()); Console.WriteLine(condition1() & condition2()); Console.WriteLine(condition1() && condition2());

断点演示:短路运算时相应condition不会被运行……

法则

如果所有参加运算成员的数值都是:

  • 2的整数次方,比方1、2、4、8、16……,或者
  • 2的整数次方数之和,比方3(=1+2)、6(=2+4)、7(=1+2+4)……

他们就会有如下法则:

  • 位或(|)相当于“加”,比方:2|4=6,2|4|1=7……,以下咱们将位或(相加)的后果简称为“位或后果”,参加位或运算的成员简称为“成员”,未参加运算的称之为“非成员”
  • 而后,将位或后果和任一成员进行异或(^)运算,其成果就相当于“减”,比方:6^2=4,7^4=3,
  • 最初,将位或后果和任一成员进行位与(&)运算,其后果就等于该成员,比方:6&2=2,7&4=4;且与任何非成进行位与(&)运算,其后果不会等于该非成员,比方:6&1=0,7&8=0

严格的数学证实,飞哥也不会,^_^,同学们就这样记住论断吧……

@想一想@,这能够用来干嘛?

作用

进行权限治理啊!

比方源栈的学生,能够是:

  • 学生(Student),还能够是
  • 老师助理(TeacherAssist),以及
  • 小组长(TeamLeader)和
  • 寝室长(DormitoryHead)

每个同学能够是下面一种或多种角色,而且能够随时增减。让你在Student类中增加一个属性记录同学的角色,你怎么办?常见的会用数组(或者当前咱们会学习的汇合),然而,更“业余”更有“逼格”的办法是:

应用枚举(即整数)代表角色,如下所示:

enum Role { Student = 1, TeacherAssist = 2, TeamLeader = 4, DormitoryHead = 8 }//留神所有枚举值必须是2的整数次方

而后对他们进行位运算:

  • | :增加权限
  • ^:剥夺权限
  • &:检测用户是否具备某项权限

    //Role为int类型 public int Role { get; set; } Student tlzz = new Student { Role = (int)Role.Student | (int)Role.TeamLeader }; tlzz.Role = tlzz.Role | (int)Role.DormitoryHead; tlzz.Role = tlzz.Role ^ (int)Role.Student; Console.WriteLine((tlzz.Role & (int)Role.TeamLeader) == (int)Role.TeamLeader);

作业:

  1. 申明一个令牌(Token)枚举,蕴含值:SuperAdmin、Admin、Blogger、Newbie、Registered。
  2. 申明一个令牌治理(TokenManager)类:
  3. 应用公有的Token枚举_tokens存储所具备的权限
  4. 裸露Add(Token)、Remove(Token)和Has(Token)办法,能够增加、删除和判断其有无某个权限
  5. User类中增加一个Tokens属性,类型为TokenManager