65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET 枚举:更上一层楼

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.53/5 (42投票s)

2006 年 7 月 13 日

CPOL

4分钟阅读

viewsIcon

98371

如何将对象与您的枚举值相关联。

引言

在本文中,我将进一步探讨枚举。 我不会介绍关于枚举的基本信息(您可以随时参考 MSDN 获取详细信息)。 我对枚举最大的不满是它只表示数值数据。 它可以灵活地表示不同的整数类型,但不能保存字符串。 枚举确实支持 ToString() 函数;但是,存在限制(我将在本文后面详细介绍)。 基本上,我希望能够使我的枚举元素与不仅仅是一个整数值相关联。 为了实现这一点,我将使用反射和属性,并尽量使我的示例尽可能简单。

使用 ToString() 和枚举

让我们创建一个简单的枚举...

public enum EmployeeType
{
    RegularEmployee,
    StoreManager,
    ChainStoreManager,
    DepartmentManager,
    Supervisor
}

基于这个简单的普通枚举,我们可以获得以下信息: 使用 ToString()String 表示形式。

EmployeeType employee = EmployeeType.ChainStoreManager;
Console.WriteLine(employee.ToString());
Console.WriteLine(EmployeeType.ChainStoreManager.ToString());

两行代码的输出相同

ChainStoreManager
ChainStoreManager

但是,如果我想得到带有空格的“连锁店经理”怎么办? 您不能创建包含空格的枚举类型,您的代码将无法编译。 这个问题有很多解决方案。

  1. 创建枚举和字符串之间的映射(使用数组或哈希表)。
  2. 使用枚举 ToString() 作为语言资源文件的键。
  3. 使用一点反射。

我将探索选项 3...

将属性与枚举一起使用

为了将字符串与枚举关联,我使用了属性。 我将从一个简单的示例开始,该示例会将我的枚举与一个字符串相关联。

public class EnumDescriptionAttribute : Attribute
{
    private string m_strDescription;
    public EnumDescriptionAttribute(string strPrinterName)
    {
        m_strDescription = strPrinterName;
    }

    public string Description
    {
        get { return m_strDescription; }
    }
}

EnumDescriptionAttribute 是一个保存字符串的简单属性。 该属性具有一个单一属性来返回描述。 现在,我将尽量保持简单。 现在我已经有了我的描述属性,我将把它与每个枚举元素关联起来。

public enum EmployeeType
{
    [EnumDescription("Regular Employee")]
    RegularEmploye,
    [EnumDescription("Store Manager")]
    StoreManager,
    [EnumDescription("Chain Store Manager")]
    ChainStoreManager,
    [EnumDescription("Department Manager")]
    DepartmentManager,
    [EnumDescription("On Floor Supervisor")]
    Supervisor
}

从枚举中获取属性值

为了从枚举中获取属性值,我必须使用反射。 这是一个例子

// setup the enum
EmployeeType employee = EmployeeType.ChainStoreManager;

// get the field informaiton
FieldInfo fieldInfo = employee.GetType().GetField("ChainStoreManager");

// get the attributes for the enum field
object[] attribArray = fieldInfo.GetCustomAttributes(false);

// cast the one and only attribute to EnumDescriptionAttribute
EnumDescriptionAttribute attrib =
    (EnumDescriptionAttribute)attribArray[0];

// write the description
console.WriteLine("Description: {0}", attrib.Description);

输出

Chain Store Manager

最重要的代码行是: FieldInfo fieldInfo = employee.GetType().GetField("ChainStoreManager");。 请注意,我硬编码了枚举元素名称 *ChainStoreManager*,但如果您返回并查看 ToString() 函数,您可以看到我可以改用 ToString()

获取描述的泛型函数

请注意,我在枚举上使用了 ToString()...

public static string GetEnumDescription(Enum enumObj)
{
    FieldInfo fieldInfo =
        enumObj.GetType().GetField(enumObj.ToString());

    object[] attribArray = fieldInfo.GetCustomAttributes(false);
    if (attribArray.Length == 0)
        return String.Empty;
    else
    {
        EnumDescriptionAttribute attrib =
            attribArray[0] as EnumDescriptionAttribute;

        return attrib.Description;
    }
}

让我们将不仅仅是一个字符串与我们的枚举元素相关联

到目前为止,我们只将描述与我们的枚举元素相关联。 但是,完全可以将任何类型的数据与我们的枚举相关联。 为了说明这一点,我将创建一个新的枚举(类似于第一个)。

public enum ManagerType
{
    StoreManager,
    ChainManager,
    Superivor
}

我还创建了一个新的属性类,ManagerAttribute,它继承自 EnumDescription,并提供两个附加信息(最低工资和最高工资)。

public class ManagerAttribute : EnumDescriptionAttribute
{
    private int m_intMinSalary;
    private int m_intMaxSalary;
    public ManagerAttribute(string strDescription,
        int intMinSalary,
        int intMaxSalary) : base(strDescription)
    {
        m_intMinSalary = intMinSalary;
        m_intMaxSalary = intMaxSalary;
    }

    public ManagerAttribute(string strDescription)
           : base(strDescription)
    {

    }

    public int MinSalary
    {
        get {return m_intMinSalary;}
        set { m_intMinSalary = value; }
    }
    public int MaxSalary
    {
        get { return m_intMaxSalary;}
        set { m_intMaxSalary = value; }
    }
}

现在,我将把一个 ManagerAttribute 与每个枚举元素相关联。 请注意,我在我的 ManagerAttribute 中使用 set 属性,因此代码更具可读性

public enum ManagerType
{
    [Manager("Store Manager", MinSalary=40000, MaxSalary=100000)]
    StoreManager,
    [Manager("Chain Manager", MinSalary=50000, MaxSalary=110000)]
    ChainManager,
    [Manager("Store Supervisor", MinSalary=30000, MaxSalary=50000)]
    Superivor
}

下一步是改进我们的泛型函数,以允许我们获取任何类型的 EnumDescriptionAttribute;使用泛型,这很容易做到!

public static T GetAttribute<T>(Enum enumObj) where T : EnumDescriptionAttribute
{
    // get field informaiton for our enum element

    FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());

    // get all the attributes associated with our enum

    object[] attribArray = fieldInfo.GetCustomAttributes(false);

    if (attribArray.Length == 0)
        return default(T);
    else
    {
        // cast the attribute and return it

        T attrib = (T)attribArray[0];
        if (attrib != null)
            return attrib;
        else
            return default(T);
    }
}

辅助函数

到目前为止,我们有两个辅助函数,一个用于获取枚举的简单字符串描述,另一个用于获取从 EnumDescriptionAttribute 继承的任何属性的更通用的函数。 您可以将这些辅助函数添加到像 EnumHelper 这样的类中; 但是,在这个例子中,我决定简单地将它们添加到现有的 EnumDescriptionAttribute 中。

public class EnumDescriptionAttribute : Attribute
{
    private string m_strDescription;
    public EnumDescriptionAttribute(string strEnumDescription)
    {
        m_strDescription = strEnumDescription;
    }

    public string Description { get { return m_strDescription; } }

    public static string GetEnumDescription(Enum enumObj)
    {
        FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());
        object[] attribArray = fieldInfo.GetCustomAttributes(false);
        if (attribArray.Length == 0)
            return String.Empty;
        else
        {
            EnumDescriptionAttribute attrib = attribArray[0]
                as EnumDescriptionAttribute;

            return attrib.Description;
        }
    }
    public static T GetAttribute<T>(Enum enumObj)
        where T : EnumDescriptionAttribute
    {
        FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());
        object[] attribArray = fieldInfo.GetCustomAttributes(false);
        if (attribArray.Length == 0)
            return default(T);
        else
        {
            T attrib = (T)attribArray[0];
            if (attrib != null)
                return attrib;
            else
                return default(T);
        }
    }
}

最后... 让我们把它们放在一起看看

要获取字符串描述,我们可以简单地这样做

string desc = EnumDescriptionAttribute.GetEnumDescription(EmployeeType.DepartmentManager);

要获取 ManagerAttribute,我们可以这样做

ManagerAttribute manager =
    EnumDescriptionAttribute.GetAttribute<ManagerAttribute>(
    EmployeeType.DepartmentManager);

Console.WriteLine("Manager: {0}, Min Salary: {1}, Max Salary {2}",
    attrib.Description,
    manager.MinSalary,
    manager.MaxSalary);

现在,您可以看到您可以使用属性将附加信息与枚举的元素相关联。

结论

好的,所以您可以看到通过简单地使用一些属性和反射,将附加信息与您的枚举元素相关联并不难。 但是,重要的是要注意,我不认为属性应该取代常见的业务对象。 我只是想表明一个枚举不必只表示一个整数值。 正如您在本文中读到的那样,您可以将枚举与字符串或任何其他类相关联。 使用属性的一个不错的优点是它易于实现,并且使代码可读。 您可以看到 ManagerType 枚举在实现 ManagerAttribute 后的可读性如何。 很容易知道每个枚举项包含什么。 我希望您喜欢阅读这篇文章,欢迎您提出任何意见或问题。

© . All rights reserved.