C# 枚举赋值篇(转载)

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

Q:我留意到Code #02中的

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

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

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

//  Code #09 
public   enum  Alignment :  byte  
{      
     Left,    
     Center,     
     Right  

注意,能被指定为枚举的底层类型的只能是如下所列的整数类型: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。例如:

//  Code #10 
public   enum  Alignment  
{     
     Left,    
//  0     
     Center,     //  1   
     Right     //  2 
}  

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

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

ExpandedBlockStart.gif Code #11
//  Code #11  
public   enum  DriveType :  sbyte  
{     
     CDRom,    
     Fixed 
=   - 2 ,    
     Network,    
     NoRootDirectory 
=   - 1 ,   
     Ram,    
     Removable 
=  Network  *  NoRootDirectory,  
     Unknown  
}  

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

A:你可以使用System.Enum的

public   static  Array GetValues(Type enumType);

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

ExpandedBlockStart.gif Code #12
//  Code #12  
//  See Code #01 for Alignment. 
  public   static   void  Main()  
{     
     Alignment[] alignments 
=  (Alignment[])Enum.GetValues( typeof (Alignment));  
     Console.WriteLine(
" Wanna see the values of Alignment's menbers? " );    
     
foreach  (Alignment a  in  alignments)     
          Console.WriteLine(
" {0:G} = {0:D} " , a);  
}  
//  Output:  
//  Wanna see the values of Alignment's menbers? 
//  Left = 0  
//  Center = 1  
//  Right = 2  

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

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

ExpandedBlockStart.gif Code #13
//  Code #13  
//  See Code #01 for Alignment.  
public   static   void  Main()  
{      
        IConvertible ic 
=  (IConvertible)Alignment.Center; 
        
int  i  =  ic.ToInt32( null );   
        Console.WriteLine(
" The value of Alignment.Center is {0}. " , i); 
}   
//  Output:  
//  The value of Alignment.Center is 1.  

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

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

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

ExpandedBlockStart.gif Code #14
//  Code #14  
public   enum  CustomerKind  
{   
     Normal 
=   90 ,  
     Vip 
=   80 ,  
     SuperVip 
=   70
     InActive 
=   100   
}   
public   class  Customer  

     
public   readonly  CustomerKind Kind; 
     
private   double  m_Payment;
     
public   double  Payment      
     {      
        
return  m_Payment  *  ( int )Kind  /   100 ;    
     }      
 
//  Code here  

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

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

A:答案是肯定的。

//  Code #15  
//  See Code #01 for Alignment.  
Alignment a  =  (Alignment) 1

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

ExpandedBlockStart.gif Code #16
//  Code #16  
//  See Code #01 for Alignment.  
class  Program  

     
static   void  Main()  
     {  
         Foo((Alignment)
12345 );    
     }   
     
static   void  Foo(Alignment a) 
     {       
      
//  Code here  
     }  
}  

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

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

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

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

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

ExpandedBlockStart.gif Code #17
//  Code #17  
//  See Code #01 for Alignment.  
static   void  Foo(Alignment a)  
{  
    
if  ( ! Enum.IsDefined( typeof (Alignment), a))    
       
throw   new  ArgumentException( " DO NOT MAKE MISCHIEF! " );     
    
//  Code here 
}  

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

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

ExpandedBlockStart.gif Code #18
//  Code #18  
//  See Code #01 for Alignment.  
static   void  Foo(Alignment a)  

     
if  (a  !=  Alignment.Left  &&  a  !=  Alignment.Center  &&   a  !=  Alignment.Right)   
          
throw   new  ArgumentException( " DO NOT MAKE MISCHIEF! " );   
    
//  Code here  
}  

或者

ExpandedBlockStart.gif Code #19
//  Code #19  
//  See Code #01 for Alignment.  
static   void  Foo(Alignment a)  
{   
     
switch (a)  
     {       
         
case  Alignment.Left:   
             Console.WriteLine(
" Cool~ " );      
             
break ;      
        
case  Alignment.Center:        
             Console.WriteLine(
" Well~ " );       
             
break ;  
        
case  Alignment.Right:     
             Console.WriteLine(
" Good~ " );   
             
break ;  
        
default :   
             Console.WriteLine(
" DO NOT MAKE MISCHIEF! " );   
             
break ;      
     }  
}  

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

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

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

ExpandedBlockStart.gif Code #20
//  Code #20  
//  See Code #01 for Alignment.  
public   static   bool  IsAlignment(Alignment a)  
{  
     
switch (a)  
     {     
        
case  Alignment.Left:    
            
return   true ;   
        
case  Alignment.Center:   
            
return   true
        
case  Alignment.Right:    
            
return   true ;
        
default :    
            
return   false ;   
     }  
}  

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

 

 

转载于:https://www.cnblogs.com/purplefox2008/archive/2009/12/09/1620149.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值