• C#之枚举?枚举!


    关于枚举的种种

    BUG吗?虫虫吗?

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Web;


    namespace 枚举值装箱为基类所实现之接口
    {
        
    enum AlignMent{Left=100,Right=1000,Center=10};
        
    class Program
        {
            
    static void Main(string[] args)
            {
                
    //著名,此试验在.NET 1.1下无法通过,1.x不支持枚举隐式装箱
                
    //试验目的:枚举值装箱成其基类所实现之接口(隐式装箱)
                
    //第一种:能够允许,说明了枚举值(值类型)能够转换为其基类实现了的接口对象,并且是显式转换
                IConvertible ic = (IConvertible)AlignMent.Center;
                
    int i = ic.ToInt32(null);
                Console.WriteLine(
    "第一次转换的枚举值Center结果为{0}", i);
                
                
    //程序暂停
                Console.ReadKey();


                Console.WriteLine();
                IConvertible ic2 
    = (System.Enum)AlignMent.Left;
                i 
    = ic2.ToInt32(null);
                Console.WriteLine(
    "第二次转换(使用的是Enum对象),结果是{0}", i);
                Console.ReadKey();

                Console.WriteLine();
                ic2 
    = AlignMent.Right;
                i 
    = ic2.ToInt32(null);
                Console.WriteLine(
    "第三次转换,是隐式转换为接口对象,结果是{0}", i);
                Console.ReadKey();
            }
        }
    }

    枚举类型都是值类型。

    System.Enum不是枚举类型,它属于引用类型.System.Enum是一个抽象类(abstract class),所有枚举类型都直接继承自它,当然也同时继承了它的所有成员。

    Q:既然System.Enum是引用类型,而枚举类型又是直接继承自System.Enum的,那为什么枚举类型却不是引用类型?

    A:这种继承关系是隐式的并由编译器负责展开,上面Code #1的Alignment枚举被展开后的IL代码如下:

      // Code #02
      .class public auto ansi sealed Aligment
             extends [mscorlib]System.Enum
      
    {
          .field 
    public static literal Aligment Left = int32(0x00000000)
          .field 
    public static literal Aligment Center = int32(0x00000001)
          .field 
    public static literal Aligment Right = int32(0x00000002)

          .field 
    public specialname rtspecialname int32 value__
      }

     

    从声明中,你可以看到Aligment的确是继承自System.Enum的,只是你不能在C#里显式声明这种继承关系。

    Q:但你好像没有回答为什么枚举类型继承自一个引用类型后,却还是值类型!

    A:你知道,所有的值类型都是System.ValueType的后代,枚举类型也不例外,枚举类型直接继承自System.Enum,而System.Enum却又直接继承自System.ValueType的,所以,枚举类型也是System.ValueType的后代。


    Q:慢着!从System.ValueType派生出来的类型不都应该是值类型吗?为什么System.Enum会是引用类型?

    A:正确的说法应该是“值类型都是System.ValueType的后代”,但System.ValueType的后代不全是值类型,System.Enum就是唯一的特例!在System.ValueType的所有后代中,除了System.Enum之外其它都是值类型。事实上,我们可以在.NET的源代码中找到System.Enum的声明:

    public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible

     

    请注意,.NET Framework SDK v2.0.3600.0 Documentation中的Enum声明是错的:

    public abstract struct Enum : IComparable, IFormattable, IConvertible


    Q:开始头晕了,究竟枚举类型、System.Enum、System.ValueType、值类型和引用类型之间存在着什么样的关系?

    A:简单的说,

    • 1. 所有枚举类型(enum type)都是值类型。
    • 2. System.Enum和System.ValueType本身是引用类型。
    • 3. 枚举类型(enum type)都是隐式的直接继承自System.Enum,并且这种继承关系只能由编译器自动展开。但System.Enum本身不是枚举类型(enum type)。
    • 4. System.Enum是一个特例,它直接继承自System.ValueType(参见Code #03),但本身却是一个引用类型。
                //目的:看System.enum是不是枚举类型;看它是不是值类型
                Type t = typeof(System.Enum);
                
    if (t.IsEnum)
                {
                    Console.WriteLine(
    "System.Enum是enum type.");
                } 
                
    else
                {
                    Console.WriteLine(
    "System.Enum<不>是enum type.");//执行这里
                }
                
    if (t.IsValueType)
                {
                    Console.WriteLine(
    "System.Enum是value type.");
                } 
                
    else
                {
                    Console.WriteLine(
    "System.Enum<不>是enum type.");//执行这里
                }
                
    //很奇怪,原因全在编译器,System.Enum很特殊.

    枚举类型可以被装箱成System.Enum、System.ValueType、System.Object或者System.IConvertible、System.IFormattable、System.IComparable。

    注意:在.NET 1.1上,枚举类型只能被装箱到System.Enum、System.ValueType、System.Object;而在.NET 2.0上,枚举类型还能被装箱到System.Enum所实现的三个接口:System.IConvertible、System.IComparable、System.IFormattable。对应的装箱操作既可以为隐式的也可以是显式的。

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

    A:你可以使用System.Enum的

    public static Array GetValues(Type enumType);

     

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

                //目的:使用System.Enum的GetValues()方法,它会返回所有枚举成员的数组
                AlignMent[] alignments=(AlignMent[])Enum.GetValues(typeof(AlignMent));
                Console.WriteLine(
    "下面列出Alignment枚举类型所有成员:");
                
    foreach (AlignMent a in alignments)
                {
                    Console.WriteLine(
    "\t{0:G}={0:D}", a);
                }

    用System.Enum的

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

    来判断是否一个整数值能够转换为枚举成员值.

      // Code #16
      
    // 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
      }

     

    这样,恶作剧的人将会收到一个警告(异常消息)

    还可以使用条件判断语句来处理这种情况:

      // Code #17
      
    // 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 #18
      
    // 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:这个时候你就需要位枚举(Bit Flags),把Code #20修改一下:

      // Code #21
      
    // I am using the FlagsAttribute to identify a bit flags.
      [Flags]
      
    public enum FontStyle
      
    {
          Bold        
    = 0x0001,
          Italic        
    = 0x0002,
          Regular        
    = 0x0004,
          Strikethrough    
    = 0x0010,
          Underline        
    = 0x0020
      }

    现在,你可以通过按位或运算来为字体指定多种风格了:

      // Code #22
      
    // See Code #21 for FontStyle.
      Font f = new Font(
            FontFamily.GenericSansSerif,
            
    12.0F,
            FontStyle.Italic 
    | FontStyle.Underline
            );
  • 相关阅读:
    第五章课后练习题
    第四章课后练习
    函数
    变量、常量及类型
    go环境搭建及编辑器安装
    Matplotlib(绘图和可视化)
    Pandas例题(以NBA球队为例)
    Pandas
    Numpy
    jupyter notebook编辑器的用法
  • 原文地址:https://www.cnblogs.com/lizunicon/p/1393467.html
Copyright © 2020-2023  润新知