C#枚举位标记Flags以及扩展方法

Enum 类

为枚举提供基类。所有定义enum EnumName 类型的基类。

枚举并不显式从继承 Enum ; 继承关系由编译器隐式处理。

但语法上不能使用 enum Pets : Enum

枚举微软官方文档

注解

枚举是一组命名常量,其基础类型为任意整型。 如果没有显式声明基础类型, Int32 则使用。 Enum 是 .NET Framework 中的所有枚举的基类。 枚举类型由 enum c # 中的关键字构造定义。

Enum 提供一些方法,用于比较此类的实例,将实例的值转换为其字符串表示形式,将数字的字符串表示形式转换为此类的实例,并创建指定枚举和值的实例。

您还可以将枚举视为位域。增加特性[Flags]。

枚举的【与、或、异或】位操作符 就相当于 枚举对应整数的【与、或、异或】位操作。获得的数字结果 转化:进行按逗号拼接多个枚举处理

枚举最佳实践

建议在定义枚举类型时使用以下最佳做法:

  • 如果未定义值为0的枚举成员,则考虑创建 None 枚举常数。 默认情况下,由公共语言运行时将用于枚举的内存初始化为零。 因此,如果未定义值为零的常量,则在创建枚举时将包含非法值。

  • 如果你的应用程序必须表示明显的默认情况,请考虑使用值为零的枚举常数来表示它。 如果没有默认的情况,请考虑使用值为零的枚举常数来指定不由任何其他枚举常量表示的大小写。

  • 不要指定保留供将来使用的枚举常量。

  • 定义将枚举常量作为值的方法或属性时,请考虑验证值。 原因在于,您可以将数值强制转换为枚举类型,即使枚举中未定义该数值。

非独占成员和 Flags 特性 

定义按位枚举和应用属性时,应使用以下最佳做法 FlagsAttribute 。

  • FlagsAttribute仅当按位运算 (and、OR、EXCLUSIVE 或) 在数值上执行时,才将自定义属性用于枚举。

  • 以2的幂(即1、2、4、8等)定义枚举常数。 这意味着组合枚举常量中的各个标志不会重叠。

  • 请考虑为常用标记组合创建枚举常数。 例如,如果您有一个枚举用于包含枚举常量和的文件 i/o 操作 Read = 1 Write = 2 ,请考虑创建一个 ReadWrite = Read OR Write 合并和标志的枚举常数 Read Write 。 此外,在某些情况下,用于合并标志的按位 "或" 运算在某些情况下可能被视为高级概念,而对于简单任务不是必需的。

  • 如果将一个负数定义为标志枚举常量,则请小心,因为许多标志位置可能设置为1,这可能会使代码混乱并鼓励编码错误。

添加枚举方法

由于枚举类型由语言结构(如 enum (c # ) 和 Enum (Visual Basic) )定义,因此不能为枚举类型定义自定义方法,而不是从类继承的方法 Enum 。 但是,可以使用扩展方法向特定的枚举类型添加功能。

测试源程序如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EnumDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //枚举的【与、或、异或】位操作符 就相当于 枚举对应整数的【与、或、异或】位操作
            Pets familyPets = Pets.Cat | Pets.Other | Pets.Dog;
            Console.WriteLine(familyPets);
            Console.WriteLine("测试位域结果【或】操作符: {0:G} 【{0:D}】", familyPets);
            int val = 100;
            Pets p = (Pets)val;
            Console.WriteLine($"测试数字转枚举【{p}】");
            string[] s = Enum.GetNames(typeof(Pets));
            Console.WriteLine($"遍历枚举的所有元素【{string.Join(",", s)}】");
            Pets pet;
            bool result = Enum.TryParse("2", true, out pet);
            Console.WriteLine($"【数字】转化结果:【{result}】,值【{pet}】");
            result = Enum.TryParse("21", true, out pet);
            Console.WriteLine($"【数字】转化结果【拼接】:【{result}】,值【{pet}】");
            result = Enum.TryParse("200", true, out pet);
            Console.WriteLine($"【不存在的数字】转化结果:【{result}】,值【{pet}】");
            result = Enum.TryParse("288", true, out pet);
            Console.WriteLine($"【超越限制的的数字】转化结果:【{result}】,值【{pet}】");
            result = Enum.TryParse("lion", true, out pet);
            Console.WriteLine($"【枚举字符串】转化结果:【{result}】,值【{pet}】");

            result = Enum.TryParse("NotExists", true, out pet);
            Console.WriteLine($"【不存在的枚举字符串】转化结果:【{result}】,值【{pet}】");

            Pets pAnd = Pets.Horse & Pets.Lion;
            Console.WriteLine($"测试【与】操作符:{pAnd}.【{(int)pAnd}】");
            Pets pXor = Pets.Horse ^ Pets.Lion;
            Console.WriteLine($"测试【异或】操作符:{pXor}.【{(int)pXor}】");
            Console.WriteLine($"测试枚举的扩展方法【{Pets.Reptile.ExtensionMethod()}】,值【{Pets.Reptile.ToString("D")}】");
            Console.ReadLine();
        }
    }

    /// <summary>
    /// 宠物枚举,范围【0~255】,使用位域
    /// </summary>
    [Flags]
    public enum Pets : byte
    {
        None = 0,
        Dog = 1,
        Cat = 2,
        Horse = 3,
        Bird = 4,
        Lion = 5,
        Rodent = 8,
        Reptile = 16,
        Other = 32
    }

    /// <summary>
    /// 扩展方法必须定义一个静态的任意类
    /// </summary>
    public static class ExtensionEnum
    {
        /// <summary>
        /// 枚举的扩展方法:类型T前面加this关键字,表示T类型的扩展方法
        /// </summary>
        /// <param name="enumValue"></param>
        /// <returns></returns>
        public static string ExtensionMethod(this Enum enumValue)
        {
            return $"这是枚举的扩展方法:【{enumValue}】";
        }
    }
}
 

运行效果:

C#枚举位标记Flags以及扩展方法