zoukankan      html  css  js  c++  java
  • C# 枚举赋值篇(转载)

    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。为了测试你是否理解,请说出下面枚举个成员的值以及你的判断理由(请用人脑而不是电脑来运行以下代码):

    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);

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

    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接口,再调用对应的方法:

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

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

    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

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

    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方法改进一下:

    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:我认为我们还可以使用条件判断语句来处理这种情况:

    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  
    }  

    或者

    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枚举新增的特性

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

    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方法高效多了。

  • 相关阅读:
    LintCode: Climbing Stairs
    LintCode: Binary Tree Postorder Traversal
    LintCode: Binary Tree Preorder Traversal
    LintCode: Binary Tree Inorder Traversal
    Lintcode: Add Two Numbers
    Lintcode: Add Binary
    LintCode: A + B Problem
    LintCode: Remove Linked List Elements
    LintCode:Fibonacci
    Lintcode开刷
  • 原文地址:https://www.cnblogs.com/liye/p/1824828.html
Copyright © 2011-2022 走看看