<NET CLR via c# 第4版>笔记 第15章 枚举类型和位标志

15.1 枚举类型

  • 枚举定义的符号是常量值. C#编译器编译时,会用数值替换符号,不再引用定义了符号的枚举类型.可能会出现一些版本问题.
  • Enum.IsDefined(Type enumType, object value)方法被经常用于参数校验:
        public void SetColor(ConsoleColor c)
        {
            if (!Enum.IsDefined(typeof(ConsoleColor), c))
            {
                throw new ArgumentOutOfRangeException(nameof(c), c, "无效颜色值");
            }
        }
  • IsDefined方法必须慎用. 首先, IsDefined总是区分大小写;其次,IsDefined相当慢,因为它在内部使用了反射.

15.2 位标志

  • 示例代码:
        [Flags]
        public enum FileAttributes
        {
            ReadOnly = 1,
            Hidden = 2,
            System = 4,
            Directory = 16,
            ......
        }

        static void Main(string[] args)
        {
            //判断文件是否隐藏
            String file = Assembly.GetEntryAssembly().Location;
            FileAttributes attributes = File.GetAttributes(file);
            Console.WriteLine("Is {0} hidden? {1}", file, (attributes & FileAttributes.Hidden) != 0);

            //使用 HasFlag 方法(不推荐)
            Console.WriteLine("Is {0} hidden? {1}", file, attributes.HasFlag(FileAttributes.Hidden));

            //设置只读和隐藏特性
            File.SetAttributes(file, FileAttributes.ReadOnly | FileAttributes.Hidden);
        }
  • 避免使用 HasFlag,因为会装箱.
  • 永远不要对位标志枚举类型使用 IsDefined 方法. 因为无论传入数字或字符串,都只能进行简单匹配,通常会返回False.

15.3 向枚举类型添加方法

  • 本身不能添加方法,但是可通过"扩展方法"实现
        // flags 中是否包含 flagToTest
        public static bool IsSet(this FileAttributes flags, FileAttributes flagToTest)
        {
            if (flagToTest == 0)
                throw new ArgumentOutOfRangeException(nameof(flagToTest), "Value must not be 0");
            return (flags & flagToTest) == flagToTest;
        }

        // flags 中是否不包含 flagToTest
        public static bool IsClear(this FileAttributes flags, FileAttributes flagToTest)
        {
            if (flagToTest == 0)
                throw new ArgumentOutOfRangeException(nameof(flagToTest), "Value must not be 0");
            return !IsSet(flags, flagToTest);
        }

        // flags 中是否包含 testFlags 中的任何一个位标志
        public static bool AnyFlagsSet(this FileAttributes flags, FileAttributes testFlags)
        {
            return (flags & testFlags) != 0;
        }

        //将 setFlags 中包含的位标志,添加到 flags 中
        public static FileAttributes Set(this FileAttributes flags, FileAttributes setFlags)
        {
            return flags | setFlags;
        }

        //从 flags 中清除 指定的位标志(clearFlags)
        public static FileAttributes Clear(this FileAttributes flags, FileAttributes clearFlags)
        {
            return flags & ~clearFlags;
        }

        //遍历 flags 中包含的位标志
        public static void ForEach(this FileAttributes flags, Action<FileAttributes> processFlag)
        {
            if (processFlag == null) throw new ArgumentNullException(nameof(processFlag));
            for (UInt32 bit = 1; bit != 0; bit <<= 1)
            {
                UInt32 temp = ((UInt32)flags) & bit;
                if (temp != 0) processFlag((FileAttributes)temp);
            }
        }

返回目录

posted on 2017-08-11 14:23  Harry(悟秀)  阅读(237)  评论(0编辑  收藏  举报