美文网首页
枚举那些事

枚举那些事

作者: 三岁能抬头 | 来源:发表于2018-10-09 15:34 被阅读0次

    枚举是什么类型?

    public enum Alignment
    {
      Left, Center, Right
    }
    

    我们先创建一个枚举Alignment
    以上Alignment枚举被展开后的IL代码如下转化为机器语言的中间语言

    .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__
    }
    

    从IL代码中可以看出Alignment枚举继承自System.Enum。但是System.Enum是引用类型,可本身继承了ValueType值类型的基类,体现了Enum的特殊性。
    接下来用typeof进行类型判断。

    Type type = typeof(Alingnment);
    //  判断
    if (type.IsEnum)
      Console.WriteLine("I'm enum type.");
    if (type.IsValueType)
      Console.WriteLine("I'm value type.");
    if (type.IsClass)
      Console.WriteLine("I'm class type.");
    

    最后的结果输出12,所以枚举是属于值类型的。

    底层类型underlying type

    回过头来看看上面的IL代码:

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

    其实Center后面的int32(0x00000001)就是枚举的底层类型也就是基础类型默认为int32,并从上至下以0为开始,递增为1
    那除了默认的int32以外,还可以自定义为其他的整数类型,注意是整数类型包括 byte, sbyte, short, ushort, int, uint, long, ulong

    public enum DriveType : sbyte
    {
        CDRom,
        Fixed = -2,
        Network,
        NoRootDirectory = -1,
        Ram,
        Removable = Network * NoRootDirectory,
        Unknown
    }
    

    以上未赋予值的,为默认定义值,所以结果如下:
    从上至下分别为:0-2-1-1012,不难发现递增始终为1

    判断枚举值是否存在

    System.Enum提供了IsDefined这个方法。
    我们先来看看这个的方法:

            //
            // 摘要:
            //     返回指定枚举中是否存在具有指定值的常数的指示。
            //
            // 参数:
            //   enumType:
            //     枚举类型。
            //
            //   value:
            //     enumType 的常数的值或名称。
            //
            // 返回结果:
            //     如果 enumType 的某个常数具有等于 value 的值,则为 true;否则为 false。
            [ComVisible(true)]
            public static bool IsDefined(Type enumType, object value);
    

    我们可以看到该方法定义的两个参数,一个是枚举类型另一个是枚举值或名称,下面自定义一个方法:

    static void Foo(Alignment a)
    {
        if (!Enum.IsDefined(typeof(Alignment), a))
    
            throw new ArgumentException("DO NOT MAKE MISCHIEF!");
        else
            Console.WriteLine(a.ToString());
    }
    

    这样如果参数a不在枚举值内,则会抛异常。如果存在那就执行你想要执行的操作。

    位标识Bit Flags

    位标识就是给枚举加上flags特性,如:

    [Flags]
    public enum Options
    {
        None=0,
        Insert = 1, //二进制: 0001
        Update = 2, //二进制: 0010
        Save = 4,   //二进制: 0100
        Delete = 8, //二进制: 1000
        Query = 16  //二进制:10000
    }
    

    先看看flags这个特性:

    //
    // 摘要:
    //     指示可以将枚举作为位域(即一组标志)处理。
    [AttributeUsage(AttributeTargets.Enum, Inherited = false)]
    [ComVisible(true)]
    public class FlagsAttribute : Attribute
    {
        //
        // 摘要:
        //     初始化 System.FlagsAttribute 类的新实例。
        public FlagsAttribute();
    }
    

    摘要:指示可以将枚举作为位域,标志为位域后就可以进行位运算,将枚举值进行多个拼接,位运算是针对二进制位进行的运算,常用的运算主要有与&,或|,非~


    以上面的Option枚举来个例子:

    Options hasOps = Options.Insert | Options.Update;
    if ((hasOps & Options.Insert) == Options.Insert)
    {
      Console.WriteLine("Has {0}", Options.Insert);
    }
    

    来看下if里面发生了什么:

    • 首先hasOps = Options.Insert | Options.Update=0001|0010,因为|运算符:1 | 0 = 1,可得结果为:0011
    • 然后括号内hasOps & Options.Insert=0011 & 0001 = 0001
    • 最后与 == 右边的Options.Insert = 0001,对比相等返回True。

    最后提一点,位枚举的赋值可以看出来是2的指数倍。
    其目的就是位运算时结果不会出现复合值,拿Save = 4来说,默认情况下Save = 3,那Insert = 1Update = 2相加就会等于Save,丢失了唯一的标识

    引文

    END

    • 如果文章内容能误导大家那真是再好不过了,嘻嘻嘻。
    • 文章内容可能持续变更,修改或添加更多内容,以确保内容的准确性。
    • 文章中大部分观点来自引文的总结,写文章的初衷是为了方便回忆。
    • 更新时间:2018-10-9

    相关文章

      网友评论

          本文标题:枚举那些事

          本文链接:https://www.haomeiwen.com/subject/mwyjaftx.html