c#图解教程第十一章枚举

沉香 沉香     2022-08-19     229

关键词:

枚举

枚举


枚举是由程序员定义的类型与类或结构一样。

  • 与结构一样,枚举是值类型,因此直接存储它们的数据,而不是分开存储成引用和数据
  • 枚举只有一种类型的成员:命名的整数值常量

例:枚举示例

关键字 枚举名称
  ↓      ↓
enum TrafficLight
{
    Green,    ←  逗号分隔,没有分号
    Yellow,
    Red
}

每个枚举类型都有一个底层整数类型,默认为int。

  • 每个枚举成员都被赋予一个底层类型的常量值
  • 在默认情况下,编译器把第一个成员赋值为0,并对每个后续成员赋的值比前一个多1
var t1=TrafficLight.Green;
var t2=TrafficLight.Yellow;
var t3=TrafficLight.Red;
Console.WriteLine("{0},\t{1}",t1,(int)t1);
Console.WriteLine("{0},\t{1}",t2,(int)t2);
Console.WriteLine("{0},\t{1}",t3,(int)t3);

设置底层类型和显式值

可以把冒号和类型名放在枚举名之后,这样就可以使用int以外的整数类型。类型可以是任何整数类型。所有成员常量都属于枚举的底层类型。

enum TrafficLight:ulong
{
    ...
}

成员常量的值可以是底层类型的任何值。枚举成员不能有重复的名称,但可以有重复的值。

enum TrafficLight
{
    Green  =10,
    Yellow =15,
    Red    =15
}
隐式成员编号

如果不初始化一个成员常量,编译器隐式给它赋一个值。
例:

enum CardSuit
{
    Hearts,    //0 因为这是第一项
    Clubs,     //1 比之前大1
    Diamonds,  //2 比之前大1,下面的以此类推
    Spades,
    MaxSuits
}
enum FaceCards
{
    //Member             //所赋的值
    Jack    =11,         //11 显式设置
    Queen,               //12 比之前大1
    King,                //13 比之前大1
    Ace,                 //14 比之前大1
    NumberOfFaceCards=4, //4 显式设置
    SomeOtherValue,      //5 比之前大1
    HighestFaceCard=Ace  //14 以上定义了Ace
}

位标志


程序员们长期使用单个字(single word)的不同位作为一组开/关标志的紧凑方法。本节将其称为标志字(flag word)。枚举提供了实现它的简便方法。

一般步骤如下。

  1. 确定需要多少个位标志,并选择一个有足够多位的无符号类型来保存它
  2. 确定每个位位置代表什么,并给它们名称。声明一个选中的整数类型枚举,每个成员由一个位位置表示
  3. 使用按位或(OR)运算符设置保持该位标志的字中的适当的位
  4. 使用按位与(AND)运算符,或HasFlag方法解开位标志

例:下面枚举表示纸牌游戏中的一副牌的选项。

  • 成员有表示二进制选项的名称
    • 每个选项由字中的一个特殊的位表示,位位置保持一个0或一个1
    • 因为一个位标志表示一个或开或关的位,所以你不会想用0作为一个成员值。它已经有了一个意思:所有的位标志都是关
  • 在16进制表示法中,每个16机制数字用4位来表示。由于位模式和16进制表示法之间的联系,所以在处理位模式时,常使用16进制而不是10进制
  • 使用Flags特性装饰(decorate)枚举实际上不必要,但可以有一些额外的便利,很快会讨论这一点。特性表现为用中括号括起来的字符串,出现在语言构造之前。在本例中,特性出现在枚举声明之前。特性在第24章阐述
[Flags]
enum CardDeckSettings:uint
{
    SingleDeck    =0x01, //位0
    LargePictures =0x02, //位1
    FancyNumbers  =0x04, //位2
    Animation     =0x08  //位3
}

要创建一个带有适当位标志的字,需要声明一个该枚举类型的变量,并使用按位或运算符设置需要的位。

CardDeckSettings ops= CardDeckSettings.SingleDeck
                     |CardDeckSettings.FancyNumbers
                     |CardDeckSettings.Animation;

判断标志字是否包含特定的位标志集,可以使用枚举类型中的HasFlag布尔方法。在标志字上调用HasFlag方法,并将要检查的位标志作为参数。如果设置了指定的位标志,HasFlag返回true,否则返回false。

bool useFancyNumbers=ops.HasFlag(CardDeckSettings.FancyNumbers);

HasFlag还可以检测多个位标志。

  • 第一行创建了一个测试字实例,叫做testFlags,设置了Animation和FancyNumbers标志位
  • 然后把叫做testFlags作为参数传给HasFlag方法
  • HasFlag检测是否测试字中的所有标志都在ops标志字中进行了设置。如果是返回true,否则返回false
CardDeckSettings testFlags=CardDeckSettings.Animation|CardDeckSettings.FancyNumbers;
bool useAnimationAndFancyNumbers=ops.HasFlag(testFlags);

另外一种判断是否设置了一个或多个指定为的方法是使用按位与运算符。

bool useFancyNumbers=
    (ops&CardDeckSettings.FancyNumbers)==CardDeckSettings.FancyNumbers;

Flags特性
[Flags]
enum CardDeckSettings:uint
{
    SingleDeck    =0x01, //位0
    LargePictures =0x02, //位1
    FancyNumbers  =0x04, //位2
    Animation     =0x08  //位3
}

Flags特性不会改变计算结果,但却提供了一些方便的特性。首先,它通知编译器、对象浏览器以及其他查看这段代码的工具,该枚举的成员不仅可以用作单独的值,还可以按位标志进行组合。这样浏览器就可以更恰当地解释该枚举类型的变量。
其次,它允许枚举的ToString方法为位标志的值提供更多的格式化信息,ToString方法以一个枚举值位参数,将其与枚举的常量成员相比较。如果与某个成员相匹配,ToString返回该成员的字符串名称。
例:没有Flags的枚举

enum CardDeckSettings:uint
{
    SingleDeck    =0x01, //位0
    LargePictures =0x02, //位1
    FancyNumbers  =0x04, //位2
    Animation     =0x08  //位3
}
class Program
{
    static void Main()
    {
        CardDeckSettings ops;
        ops=CardDeckSettings.FancyNumbers;
        Console.WriteLine(ops.ToString());
        ops=CardDeckSettings.FancyNumbers|CardDeckSettings.Animation;
        Console.WriteLine(ops.ToString());
    }
}

上面输出结果的第二行12=8+4。因为FancyNumbers将位设置为值4,Animation将位设置为值8。
然而,如果在枚举声明前加上Flags特性,将告诉ToString方法位可以分开考虑。运行包含Flags特性的代码,结果如下:


使用位标志的示例
[Flags]
enum CardDeckSettings:uint
{
    SingleDeck    =0x01, //位0
    LargePictures =0x02, //位1
    FancyNumbers  =0x04, //位2
    Animation     =0x08  //位3
}
class MyClass
{
    bool UseSingleDeck               =false,
         UseBigPics                  =false,
         UseFancyNumbers             =false,
         UseAnimation                =false,
         UseAnimationAndFancyNumbers =false;
    public void SetOptions(CardDeckSettings ops)
    {
        UseSingleDeck=ops.HasFlag(CardDeckSettings.SingleDeck);
        UseBigPics=ops.HasFlag(CardDeckSettings.LargePictures);
        UseFancyNumbers=ops.HasFlag(CardDeckSettings.FancyNumbers);
        UseAnimation=ops.HasFlag(CardDeckSettings.Animation);
        CardDeckSettings testFlags=CardDeckSettings.Animation|CardDeckSettings.FancyNumbers;
        UseAnimationAndFancyNumbers=ops.HasFlag(testFlags);
    }
    public void PrintOptions()
    {
        Console.WriteLine("Option settings:");
        Console.WriteLine("Use Single Deck                   - {0}",UseSingleDeck);
        Console.WriteLine("Use Large Pictures                - {0}",UseBigPics);
        Console.WriteLine("Use Fancy Numbers                 - {0}",UseFancyNumbers);
        Console.WriteLine("Show Animation                    - {0}",UseAnimation);
        Console.WriteLine("Show Animation And FancyNumbers   - {0}",UseAnimationAndFancyNumbers);
    }
}
class Program
{
    static void Main()
    {
        var mc=new MyClass();
        CardDeckSettings ops=CardDeckSettings.SingleDeck
                             |CardDeckSettings.FancyNumbers
                             |CardDeckSettings.Animation;
        mc.SetOption(ops);
        mc.PrintOptions();
    }
}

关于枚举的补充


枚举只有单一的成员类型:声明的成员常量

  • 不能对成员使用修饰符。它们都隐式地具有和枚举相同的可访问性
  • 由于成员是常量,即使在没有该枚举变量时也可以访问。使用枚举类型名.成员名

例:直接访问枚举常量

Console.WriteLine("{0}",TrafficLight.Green);

枚举是一种独特的类型。比较不同枚举类型的成员会导致编译时错误。
例: 枚举比较

  • 第一个if正确,因为它比较同一枚举类型的不同成员
  • 第二个if会产生一个错误,因为它比较来自不同枚举类型的成员,尽管它们的结构和成员名称相同
enum FirstEnum
{
    Mem1,
    Mem2
}
enum SecondEnum
{
    Mem1,
    Mem2
}
class Program
{
    static void Main()
    {
        if(FirstEnum.Mem1<FirstEnum.Mem2)
            Console.WriteLine("True");
        if(FirstEnum.Mem1<SecondEnum.Mem1)  //错误,不同枚举类型
            Console.WriteLine("True");
    }
}

.NET Enum类型还包括一些有用的静态方法:

  • GetName方法以枚举类型对象和整数为参数,返回响应的枚举成员的名称
  • GetNames方法以枚举类型对象为参数,返回该枚举中所有成员的名称

例:GetName、GetNames示例

enum TrafficLight
{
    Green,
    Yellow,
    Red
}
class Program
{
    static void Main()
    {
        Console.WriteLine("Second member of TrafficLight is {0}\n",Enum.GetName(typeof(TrafficLight),1));
        foreach(var name in Enum.GetNames(typeof(TrafficLight)))
        {
            Console.WriteLine(name);
        }
    }
}

第十一章

因为是手机上传,有些图没有上传好,晚上回去重新弄。 查看详情

第十一章网络编程

--------------------------------------------------------Sun11Feb13:30:10GMT2018--------------------------------------------------------第十一章网络编程11.1Theclient-ServerprogrammingModelThefundamentaloperati 查看详情

[学习笔记—objective-c]《objective-c-基础教程第2版》第十一章属性

11.1使用属性值@propertyfloatrainHandling;//表明此类具有float类型的属性,其名称为rainHandling注意:属性的名称不必与实例变量名称同样。@synthesizerainHandling;//表示创建了该属性的訪问代码注意:使用属性后,能够不声明实例变量。编... 查看详情

第十一章

一.分组查询   1.语法    SELECT...FROM...GROUPBY...    --分组查询Groupby    selectCOUNT(*)as学生人数,GradeIdas年级编号fromStudentgroupbyGradeId&n 查看详情

高数(a)下第十一章(持续更新)

11.1 11.2 查看详情

第十一章linq

DataLibusingSystem;usingSystem.Collections.Generic;namespaceWrox.ProCSharp.LINQ{[Serializable]publicclassTeam{publicTeam(stringname,paramsint[]years){this.Name=name;this.Years=newList<int>(years 查看详情

html第十一章总结

#第十一章总结:本章的标题为:layoutandpositioningArrangingElement##前言:这一章节,通过已经知道的boxmodel的概念,进行讲述关于layout的知识,并且通过这些知识进行创造专业的设计和multicolumnlayouts.##谈谈Flow###对于blockelement*对blockeleme... 查看详情

第十一章多元线性回归与相关分析

  查看详情

第十一章线程

第十一章线程11.3线程标识每个线程也有一个线程ID,线程ID只有在它所属的进程上下文中才有意义。/* 比较两个线程ID,相等返回非0数值,否则返回0*/#include<pthread.h>intpthread_equal(pthread_ttid1,pthread_ttid2); /* 获得自身... 查看详情

第十一章

(1)1.万物皆对象:(地球上有什么?我们会不自觉的将地球上的事物归为具体类别) 2.对象:顾客   ,   收银员;               官方定义:用来... 查看详情

第十一章笔记

                                 &n 查看详情

第十一章习题答案

第十一章练习题答案?1.如何把/etc/passwd中用户uid大于500的行给打印出来?awk-f‘:‘‘$3>500‘/etc/passwd?2.awk中nr,nf两个变量表示什么含义awk-f‘:‘‘{print$nr}‘/etc/passwd会打印出什么结果出来?nr表示行数,nf表示一共有多少段?awk-f‘:... 查看详情

“全栈2019”java第十一章:标识符

...开发环境JDKv11IntelliJIDEAv2018.3文章原文链接“全栈2019”Java第十一章:标识符下一章“全栈2019”Java第十二章:变量学习小组加入同步学习小组,共同交流与进步。方式一:关注头条号Gorhaf,私信“Java学习小组”。方式二:关注公... 查看详情

第十一章:dom扩展

DOM扩展选择符APIquerySelector方法querySelectorAll方法matchesSelector方法元素遍历HTML5与类相关的补充getElementsByClassName方法classList属性焦点管理HTMLDocument的变化readyState属性兼容模式head属性字符集属性自定义数据属性插入标记innerHTML属性ou... 查看详情

c#图解教程第十九章linq

LINQ什么是LINQLINQ提供程序匿名类型方法语法和查询语法查询变量查询表达式的结构from子句join子句什么是联结查询主体中的from…let…where片段from子句let子句where子句orderby子句select…group子句查询中的匿名类型group子句查询延续:in... 查看详情

c#图解教程第十三章委托

委托什么是委托委托概述声明委托类型创建委托对象给委托赋值组合委托为委托添加方法从委托移除方法调用委托委托示例调用带返回值的委托调用带引用参数的委托匿名方法使用匿名方法匿名方法的语法Lambda表达式委托什么是... 查看详情

c#图解教程第十五章接口

接口什么是接口使用IComparable接口的示例声明接口实现接口简单接口示例接口是引用类型接口和as运算符实现多个接口实现具有重复成员的接口多个接口的引用派生成员作为实现显式接口成员实现访问显式接口成员实现接口可以... 查看详情

第十一章

一、理解什么是类和对象万事万物皆对象   1、属性——对象具有的特征(特点)   2、方法——对象可执行的操作(能干什么事)   3、对象的定义:是一个客观存在的,看的见或摸得着的实体,... 查看详情