zoukankan      html  css  js  c++  java
  • 深入浅出OOP(六): 理解C#的Enums

    MSDN定义:枚举类型(也称为枚举)为定义一组可以赋给变量的命名整数常量提供了一种有效的方法。  例如,假设您必须定义一个变量,该变量的值表示一周中的一天。

    该变量只能存储七个有意义的值。 若要定义这些值,可以使用枚举类型。枚举类型是使用 enum 关键字声明的。

    image

    从OOP上来说,枚举的角色和和class一样,它创建了一种新的数据类型。

      1: namespace Enums
    
      2: {
    
      3:     class Program
    
      4:     {
    
      5:         static void Main(string[] args)
    
      6:         {
    
      7:         }
    
      8:     }
    
      9: 
    
     10:     enum Color
    
     11:     {
    
     12:         Yellow,
    
     13:         Blue,
    
     14:         Brown,
    
     15:         Green
    
     16:     }
    
     17: }

    上面的代码,我们使用enum的关键字,创建了新的数据类型Color,并包含4个值:Yellow, Blue, Brown和Green。下面的例子我们给予Color枚举。

    直接输出枚举,则可得到枚举的字符

      1: using System;
    
      2: namespace Enums
    
      3: {
    
      4:     class Program
    
      5:     {
    
      6:         static void Main(string[] args)
    
      7:         {
    
      8:             Console.WriteLine(Color.Yellow);
    
      9:             Console.ReadLine();
    
     10:         }
    
     11:     }
    
     12: 
    
     13:     enum Color
    
     14:     {
    
     15:         Yellow,
    
     16:         Blue,
    
     17:         Brown,
    
     18:         Green
    
     19:     }
    
     20: }

    运行程序,输出:

    Yellow

    强转为int型,输出试试看:

      1: using System;
    
      2: namespace Enums
    
      3: {
    
      4:     class Program
    
      5:     {
    
      6:         static void Main(string[] args)
    
      7:         {
    
      8:             Console.WriteLine((int)Color.Yellow);
    
      9:             Console.ReadLine();
    
     10:         }
    
     11:     }
    
     12: 
    
     13:     enum Color
    
     14:     {
    
     15:         Yellow,
    
     16:         Blue,
    
     17:         Brown,
    
     18:         Green
    
     19:     }
    
     20: }

    结果输出:

    0

    从上面的例子中,我们可以看到枚举的使用,如同static变量一样,可被直接使用。如不用转换则默认输出枚举定义的字符,强转后

    则输出枚举对应的数字值---故枚举可表达恒量数值,或者命名的字符串标示。

    基础数据类型

      1: using System;
    
      2: namespace Enums
    
      3: {
    
      4:     class Program
    
      5:     {
    
      6:         static void Main(string[] args)
    
      7:         {
    
      8:             Console.WriteLine((byte)Color.Yellow);
    
      9:             Console.WriteLine((byte)Color.Blue);
    
     10:             Console.ReadLine();
    
     11:         }
    
     12:     }
    
     13: 
    
     14:     enum Color:byte
    
     15:     {
    
     16:         Yellow,
    
     17:         Blue,
    
     18:         Brown,
    
     19:         Green
    
     20:     }
    
     21: }

    结果输出为:

    0

    1

    这里唯一做的修改是枚举Color继承自byte ,而不是默认的int型。

    枚举可继承自数值型类型,如long, ulong, short, ushort, int, uint, byte sbyte。但是无法继承自char类型。

    枚举可被枚举继承吗?

      1: using System;
    
      2: namespace Enums
    
      3: {
    
      4:     class Program
    
      5:     {
    
      6:         static void Main(string[] args)
    
      7:         {
    
      8:             Console.WriteLine((byte)Color.Yellow);
    
      9:             Console.WriteLine((byte)Color.Blue);
    
     10:             Console.ReadLine();
    
     11:         }
    
     12:     }
    
     13: 
    
     14:     enum Color:byte
    
     15:     {
    
     16:         Yellow,
    
     17:         Blue,
    
     18:         Brown,
    
     19:         Green
    
     20: 
    
     21:     }
    
     22: 
    
     23:     enum Shades:Color
    
     24:     {
    
     25: 
    
     26:     }
    
     27: }

    编译,报错:

    Type byte, sbyte, short, ushort, int, uint, long, or ulong expected.

    枚举可被class继承吗?

      1:   enum Color:byte
    
      2:     {
    
      3:         Yellow,
    
      4:         Blue,
    
      5:         Brown,
    
      6:         Green
    
      7:     }
    
      8: 
    
      9: class Derived:Color
    
     10:     {
    
     11: 
    
     12:     }

    编译报错:

    'Enums.Derived': cannot derive from sealed type 'Enums.Color'

    接下来,我们看看枚举和这3个接口的关系:IComparable, IFormattable 和IConvertible。

    A. IComparable

      1: using System;
    
      2: 
    
      3: namespace Enums
    
      4: {
    
      5:     internal enum Color
    
      6:     {
    
      7:         Yellow,
    
      8:         Blue,
    
      9:         Green
    
     10:     }
    
     11: 
    
     12:     internal class Program
    
     13:     {
    
     14:         private static void Main(string[] args)
    
     15:         {
    
     16:             Console.WriteLine(Color.Yellow.CompareTo(Color.Blue));
    
     17:             Console.WriteLine(Color.Blue.CompareTo(Color.Green));
    
     18:             Console.WriteLine(Color.Blue.CompareTo(Color.Yellow));
    
     19:             Console.WriteLine(Color.Green.CompareTo(Color.Green));
    
     20:             Console.ReadLine();
    
     21:         }
    
     22:     }
    
     23: }

    结果输出:

    -1

    -1

    1

    0

    -1表示小于关系,0表示等于关系,1表示大于关系。这里标明了enum默认继承了IComparable接口,故有CompareTo()函数。

    B. IFormattable

      1: using System;
    
      2: 
    
      3: namespace Enums
    
      4: {
    
      5:     internal enum Color
    
      6:     {
    
      7:         Yellow,
    
      8:         Blue,
    
      9:         Green
    
     10:     }
    
     11: 
    
     12:     internal class Program
    
     13:     {
    
     14:         private static void Main(string[] args)
    
     15:         {
    
     16:             System.Console.WriteLine(Color.Format(typeof(Color), Color.Green, "X"));
    
     17:             System.Console.WriteLine(Color.Format(typeof(Color), Color.Green, "d"));
    
     18:             Console.ReadLine();
    
     19:         }
    
     20:     }
    
     21: }

    结果输出:

    00000002

    2

    Format方法继承自IFormatter 接口,它是一个static函数,因此可以被枚举Color直接使用。format需要传入3个参数,第一个是枚举的类型,

    第二个参数是枚举值,第三个是格式化标示---二进制、十进制等。

    C. IConvertible

      1: Hide   Copy Code
    
      2: using System;
    
      3: 
    
      4: namespace Enums
    
      5: {
    
      6:      enum Color
    
      7:     {
    
      8:         Yellow,
    
      9:         Blue,
    
     10:         Green
    
     11:     }
    
     12: 
    
     13:     internal class Program
    
     14:     {
    
     15:         private static void Main(string[] args)
    
     16:         {
    
     17:             string[] names;
    
     18:             names = Color.GetNames(typeof (Color));
    
     19:             foreach (var name in names)
    
     20:             {
    
     21:                 Console.WriteLine(name);
    
     22:             }
    
     23:             Console.ReadLine();
    
     24:         }
    
     25:     }
    
     26: }
    
     27: 

    结果输出:

    Yellow

    Blue

    Green

    GetNames函数是枚举Color的静态方法,用于获得枚举所有的字符标示名称集合。

    同理也可使用ToString输出枚举的字符标示:

      1: using System;
    
      2: 
    
      3: namespace Enums
    
      4: {
    
      5:      enum Color
    
      6:     {
    
      7:         Yellow,
    
      8:         Blue,
    
      9:         Green
    
     10:     }
    
     11: 
    
     12:     internal class Program
    
     13:     {
    
     14:         private static void Main(string[] args)
    
     15:         {
    
     16:            Console.WriteLine(Color.Blue.ToString());
    
     17:            Console.WriteLine(Color.Green.ToString());
    
     18:            Console.ReadLine();
    
     19:         }
    
     20:     }
    
     21: }

    显示输出:

    Blue

    Green

    上面的例子显示,枚举可在int和string直接转换,这个特性是枚举使用中非常重要的一个功能。

    试试看,枚举的字符标示是否可以重复定义:

      1: using System;
    
      2: namespace Enums
    
      3: {
    
      4:     class Program
    
      5:     {
    
      6:         static void Main(string[] args)
    
      7:         {
    
      8:             Console.WriteLine((byte)Color.Yellow);
    
      9:             Console.WriteLine((byte)Color.Blue);
    
     10:             Console.ReadLine();
    
     11:         }
    
     12:     }
    
     13: 
    
     14:     enum Color
    
     15:     {
    
     16:         Yellow,
    
     17:         Blue,
    
     18:         Brown,
    
     19:         Green,
    
     20:         Blue
    
     21:     }
    
     22: }

    编译报错,结果:

    Compile time error: The type 'Enums.Color' already contains a definition for 'Blue'

    可见枚举中不能定义重复的字符标示。

    再看另外一个例子:

      1: using System;
    
      2: namespace Enums
    
      3: {
    
      4:     class Program
    
      5:     {
    
      6:         static void Main(string[] args)
    
      7:         {
    
      8:             Console.WriteLine((int)Color.Yellow);
    
      9:             Console.WriteLine((int)Color.Blue);
    
     10:             Console.WriteLine((int)Color.Brown);
    
     11:             Console.WriteLine((int)Color.Green);
    
     12: 
    
     13:             Console.ReadLine();
    
     14:         }
    
     15:     }
    
     16: 
    
     17:     enum Color
    
     18:     {
    
     19:         Yellow =2,
    
     20:         Blue,
    
     21:         Brown=9,
    
     22:         Green,
    
     23: 
    
     24:     }
    
     25: }

    结果:

    2

    3

    9

    10

    从结果看,我们可以在枚举定义的时候重新指定数值,如我们指定了yellow为2,则Blue默认为Yellow+1,为3. 下来,我们指定了Brown为9,则

    其下的Green为Brown + 1,为10。 这是一个有趣的enum特性。

    如指定的数据类型超过枚举的定义类型,如何?

      1: using System;
    
      2: namespace Enums
    
      3: {
    
      4:     class Program
    
      5:     {
    
      6:         static void Main(string[] args)
    
      7:         {
    
      8: 
    
      9:         }
    
     10:     }
    
     11: 
    
     12:     enum Color:byte
    
     13:     {
    
     14:         Yellow =300 ,
    
     15:         Blue,
    
     16:         Brown=9,
    
     17:         Green,
    
     18:     }
    
     19: }

    编译报错:

    Compile time error: Constant value '300' cannot be converted to a 'byte'

    300超出了byte数据类型的范围,故报错。 枚举的类型检测非常好,在项目使用中很实用的功能。

    枚举引用代码

      1: using System;
    
      2: namespace Enums
    
      3: {
    
      4:     class Program
    
      5:     {
    
      6:         static void Main(string[] args)
    
      7:         {
    
      8:             Console.WriteLine((int)Color.Yellow);
    
      9:             Console.WriteLine((int)Color.Blue);
    
     10:             Console.WriteLine((int)Color.Brown);
    
     11:             Console.WriteLine((int)Color.Green);
    
     12: 
    
     13:             Console.ReadLine();
    
     14:         }
    
     15:     }
    
     16: 
    
     17:     enum Color
    
     18:     {
    
     19:         Yellow = 2,
    
     20:         Blue,
    
     21:         Brown = 9,
    
     22:         Green = Yellow
    
     23:     }
    
     24: }

    结果输出:

    2

    3

    9

    2

    这里,我们定义Green的值,引用了Color的Yellow枚举值。

    枚举,是否可以在外面修改枚举值:

      1: using System;
    
      2: namespace Enums
    
      3: {
    
      4:     class Program
    
      5:     {
    
      6:         static void Main(string[] args)
    
      7:         {
    
      8:             Color.Yellow = 3;
    
      9:         }
    
     10:     }
    
     11: 
    
     12:     enum Color
    
     13:     {
    
     14:         Yellow = 2,
    
     15:         Blue,
    
     16:         Brown = 9,
    
     17:         Green = Yellow
    
     18:     }
    
     19: }

    运行结果:

    Compile time error: The left-hand side of an assignment must be a variable, property or indexer

    编译报错了。可见枚举数值是常量,仅在初始化的时候确定,外部无法动态修改。

    那么,枚举是否可以循环依赖?

      1: using System;
    
      2: 
    
      3: namespace Enums
    
      4: {
    
      5:     internal enum Color
    
      6:     {
    
      7:         Yellow=Blue,
    
      8:         Blue
    
      9:     }
    
     10: 
    
     11:     internal class Program
    
     12:     {
    
     13:         private static void Main(string[] args)
    
     14:         {
    
     15:         }
    
     16:     }
    
     17: }

    编译结果:

    Compile time error: The evaluation of the constant value for 'Enums.Color.Yellow' involves a circular definition

    保留关键字

    image

      1: using System;
    
      2: 
    
      3: namespace Enums
    
      4: {
    
      5:      enum Color
    
      6:     {
    
      7:       value__
    
      8:     }
    
      9: 
    
     10:     internal class Program
    
     11:     {
    
     12:         private static void Main(string[] args)
    
     13:         {
    
     14: 
    
     15:         }
    
     16:     }
    
     17: }

    编译报错:

    Compile time error: The enumerator name 'value__' is reserved and cannot be used

    原因很简单,这里的value__是保留关键字。

    枚举小结:

    1. enum表达了恒定的数值,枚举类型可以用字符串标示
    2. 无法声明char基础类型的枚举
    3. enum仅仅能继承自byte, sbyte, short, ushort, int, uint, long, 或ulong数据类型
    4. 默认的,enum是一个sealed类,既无法被继承
    5. enum类型隐式实现了System.Enum
    6. enum类型继承了3个接口:IComparable, IFormattable和IConvertible
    7. enum中,数字和字符串可以互相转换
    8. enum的值可被初始化为同样的值
    9. enum的值要在初始化时候确定
    10. enum中,'value__'关键字不能使用

    原文:Diving in OOP (Day 6): Understanding Enums in C# (A Practical Approach)

    文章目录:

  • 相关阅读:
    递归的效率问题以及递归与循环的比较
    malloc/free与new/delete的区别
    类的综合案例——纯虚函数与抽象类( 加强对接口与多态,以及派生类构造函数的理解 )
    对象移动、右值引用详解
    深入理解类成员函数的调用规则(理解成员函数的内存为什么不会反映在sizeof运算符上、类的静态绑定与动态绑定、虚函数表)
    为什么NULL指针也能访问成员函数?(但不能访问成员变量)
    洛谷P1656 炸铁路
    Vijos1901 学姐的钱包
    洛谷P2327 [SCOI2005] 扫雷
    洛谷P1993 小 K 的农场
  • 原文地址:https://www.cnblogs.com/powertoolsteam/p/Diving-in-OOP-Day-Understanding-Enums-in-Csharp-A.html
Copyright © 2011-2022 走看看