深入浅出OOP(六): 理解C#的Enums

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

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

深入浅出OOP(六): 理解C#的Enums

从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型。

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

枚举可被枚举继承吗?

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

保留关键字

深入浅出OOP(六): 理解C#的Enums

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)

PS:如果您想和业内技术大牛交流的话,请加qq群(527933790)或者关注微信公众 号(AskHarries),谢谢!

转载请注明原文出处:Harries Blog™ » 深入浅出OOP(六): 理解C#的Enums

赞 (0)

分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址