有关C#枚举的问答集锦:有关赋值

开发 后端
本文汇总了一些有关C#枚举的问答。本文是第二部分,汇总了一些有关枚举赋值的相关问答。

本文继续介绍C#枚举的常见问题与答案。

Q:我留意到Code #02中的

.field public static literal Aligment Center = int32(0x00000001)

该语句明显是整数赋值,这是否说明C#枚举类型实质上是整数类型?

A:这说明枚举类型与整数类型的确有一定的关系。事实上,每一个枚举类型都有与之相对应的整数类型,我们称该整数类型为底层类型(underlying type),默认的情况下使用,.NET使用System.Int32。当然,你可以手动将其指定为其他的整数类型:

  1. // Code #09  
  2. public enum Alignment : byte 
  3. {  
  4.     Left,  
  5.     Center,  
  6.     Right  
  7. }  

注意,能被指定为枚举的底层类型的只能是如下所列的整数类型:byte, sbyte, short, ushort, int, uint, long, ulong。

--------------------------------------------------------------------------------

Q:为何我们需要指定枚举类型的底层类型?

A:你完全可以让它接受默认的底层类型。请留意Code #08,你完全找不到“Center”这个字眼,然而在C#代码中,它却是存在的,为什么呢?这是因为代码在编译的时候,编译器把枚举类型转换为与之对应的底层类型的数值来处理。Code #08的L_0000实际上就是把类型为System.Int32的数值1推入堆栈,而不是把“Center”推入堆栈。事实上,底层类型说明了如何为枚举类型分配空间,不同的底层类型所占用的资源不同,大概当你在受限系统上进行开发的话,你就可能需要注意一下了。

--------------------------------------------------------------------------------

C#枚举的赋值

Q:枚举成员的值是怎样规定的?

A:如果你没有手动指定成员的值的话,从上往下看,各成员的值为:0, 1, 2, ...。说罢了,就是一个非负整数等差数列,其初值为0,步长为1。例如:

  1. // Code #10  
  2. public enum Alignment  
  3. {  
  4.     Left,    // 0  
  5.     Center,    // 1  
  6.     Right    // 2  
  7. }  

--------------------------------------------------------------------------------

Q:如果我有手动指定某些成员的值呢?

A:那么被赋值的成员的值就是你所指定的值。当然,无论你是否手动指定枚举成员的值,递增步长都不会变,总是为1。为了测试你是否理解,请说出下面枚举个成员的值以及你的判断理由(请用人脑而不是电脑来运行以下代码):

  1. // Code #11  
  2. public enum DriveType : sbyte 
  3. {  
  4.     CDRom,  
  5.     Fixed = -2,  
  6.     Network,  
  7.     NoRootDirectory = -1,  
  8.     Ram,  
  9.     Removable = Network * NoRootDirectory,  
  10.     Unknown  
  11. }  

--------------------------------------------------------------------------------

Q:我们如何获取枚举成员的值,无论成员是否被手动赋值?

A:你可以使用System.Enum的

  1. public static Array GetValues(Type enumType); 

该方法返回一个包含所有枚举成员的数组:

  1. // Code #12  
  2. // See Code #01 for Alignment.  
  3. public static void Main()  
  4. {  
  5.     Alignment[] alignments = (Alignment[])Enum.GetValues(typeof(Alignment));  
  6.     Console.WriteLine("Wanna see the values of Alignment's menbers?");  
  7.     foreach (Alignment a in alignments)  
  8.         Console.WriteLine("{0:G} = {0:D}", a);  
  9. }  
  10.  
  11. // Output:  
  12. // Wanna see the values of Alignment's menbers?  
  13. // Left = 0  
  14. // Center = 1  
  15. // Right = 2  

--------------------------------------------------------------------------------

Q:如果我只需要其中某些枚举成员的值呢?

A:那么你可以把枚举转换为IConvertible接口,再调用对应的方法:

  1. // Code #12  
  2. // See Code #01 for Alignment.  
  3. public static void Main()  
  4. {  
  5.     IConvertible ic = (IConvertible)Alignment.Center;  
  6.     int i = ic.ToInt32(null);  
  7.     Console.WriteLine("The value of Alignment.Center is {0}.", i);  
  8. }  
  9.  
  10. // Output:  
  11. // The value of Alignment.Center is 1.  

--------------------------------------------------------------------------------

Q:为什么需要手动指定枚举成员的值?

A:一般情况下,使用默认的赋值规则就足够了,但某些情况下,为枚举成员指定一个与实际情况(模型)相符的值可能更有意义,这要视你具体所建的模型而定。

还是让我们来一个实际的例子:

  1. // Code #13  
  2. public enum CustomerKind  
  3. {  
  4.     Normal = 90,  
  5.     Vip = 80,  
  6.     SuperVip = 70,  
  7.     InActive = 100  
  8. }  
  9.  
  10. public class Customer  
  11. {  
  12.     public readonly CustomerKind Kind;  
  13.  
  14.     private double m_Payment;  
  15.     public double Payment  
  16.     {  
  17.         return m_Payment * (int)Kind / 100;  
  18.     }  
  19.  
  20.     // Code here  
  21. }  

我为枚举CustomerKind的每个成员都赋了一个特定的值,该值其实就是顾客购物折扣百分率。而在Customer类中,Payment属性就通过强类型转换来获取枚举成员的值(也就是购物折扣率),并用于货款计算。从这里可以看出,获取枚举成员的值还可以通过强类型转换方式。

--------------------------------------------------------------------------------

Q:既然枚举类型可以强制转换为整数,那么整数是否也可以强制转换为枚举类型?

A:答案是肯定的。

  1. // Code #14  
  2. // See Code #01 for Alignment.  
  3. Alignment a = (Alignment)1;  

但这种机制可能使你遇到一些麻烦:

  1. // Code #15  
  2. // See Code #01 for Alignment.  
  3. class Program  
  4. {  
  5.     static void Main()  
  6.     {  
  7.         Foo((Alignment)12345);  
  8.     }  
  9.  
  10.     static void Foo(Alignment a)  
  11.     {  
  12.         // Code here  
  13.     }  
  14. }  

你无法避免有人进行这样的恶作剧!!

--------------------------------------------------------------------------------

Q:那么是否有办法对付这些恶作剧的人?

A:Sure!我们总不能假设人人都那么守规矩,所以,我们需要System.Enum的

  1. public static bool IsDefined(Type enumType, object value);  
  2.  

现在我们把Code #15的Foo方法改进一下:

  1. // Code #16  
  2. // See Code #01 for Alignment.  
  3. static void Foo(Alignment a)  
  4. {  
  5.     if (!Enum.IsDefined(typeof(Alignment), a))  
  6.         throw new ArgumentException("DO NOT MAKE MISCHIEF!");  
  7.  
  8.     // Code here  
  9. }  

这样,恶作剧的人将会收到一个警告(异常消息)。当然,我们不排除有人是由于一时大意才造成这样的“恶作剧”,那么IsDefined方法同样可以帮助你处理好这些情况。

--------------------------------------------------------------------------------

Q:我认为我们还可以使用条件判断语句来处理这种情况:

  1. // Code #17  
  2. // See Code #01 for Alignment.  
  3. static void Foo(Alignment a)  
  4. {  
  5.     if (a != Alignment.Left &&  
  6.         a != Alignment.Center &&  
  7.         a != Alignment.Right)  
  8.         throw new ArgumentException("DO NOT MAKE MISCHIEF!");  
  9.  
  10.     // Code here  
  11. }  

或者

  1. // Code #18  
  2. // See Code #01 for Alignment.  
  3. static void Foo(Alignment a)  
  4. {  
  5.     switch(a)  
  6.     {  
  7.         case Alignment.Left:  
  8.             Console.WriteLine("Cool~");  
  9.             break;  
  10.         case Alignment.Center:  
  11.             Console.WriteLine("Well~");  
  12.             break;  
  13.         case Alignment.Right:  
  14.             Console.WriteLine("Good~");  
  15.             break;  
  16.         default:  
  17.             Console.WriteLine("DO NOT MAKE MISCHIEF!");  
  18.             break;  
  19.     }  
  20. }  

A:你绝对可以这样做!事实上,如果你处于以下情况之一的话:

1. Alignment枚举代码不会被修改
2. 你不希望使用Alignment枚举新增的特性

那么我会推荐使用你的处理方式。而且,你还可以为自己的代码定义一个这样的方法:

  1. // Code #19  
  2. // See Code #01 for Alignment.  
  3. public static bool IsAlignment(Alignment a)  
  4. {  
  5.     switch(a)  
  6.     {  
  7.         case Alignment.Left:  
  8.             return true;  
  9.         case Alignment.Center:  
  10.             return true;  
  11.         case Alignment.Right:  
  12.             return true;  
  13.         default:  
  14.             return false;  
  15.     }  
  16. }  

这个方法比起IsDefine方法高效多了。

--------------------------------------------------------------------------------

以上就总结了一些C#枚举赋值的相关问答。

【编辑推荐】

  1. 有关C#枚举的问答集锦:基础篇
  2. C#枚举和数学习经验总结
  3. 浅谈如何利用C#枚举所有的窗体
  4. C#记忆功能的地址栏控件
  5. 描述C#调用外部进程
责任编辑:yangsai 来源: CSDN博客
相关推荐

2009-08-11 14:44:24

C#枚举

2009-08-11 15:24:03

C#枚举

2010-08-12 18:01:38

ibmdwJazz

2010-12-29 09:51:06

配置vsftpdDebian

2011-06-13 10:30:07

Linus Torva

2009-06-11 13:00:08

Java数组赋值

2012-07-05 09:42:08

jQuery

2010-06-02 13:30:10

IPv6标准

2010-03-12 09:47:22

2009-08-18 10:30:30

C#枚举

2018-02-06 10:07:18

RAID 5磁盘阵列数据恢复

2009-08-21 18:05:23

ASP.NET Ses

2011-03-03 13:25:57

2009-08-13 14:52:21

.NET性能误区C#和VB.NET

2010-01-28 13:15:43

C++参数

2010-01-18 16:14:43

配置VLAN交换机

2010-01-20 09:14:49

C语言模块化

2018-01-31 10:58:27

2009-12-29 14:41:12

ADSL常见硬件问题

2009-08-17 18:31:39

C# 枚举
点赞
收藏

51CTO技术栈公众号