嵌套枚举的替代方案

5
我试图创建几个枚举,其语法为Dropdown.Category.Subcategory,但是我读到这并不是一个好主意。我选择这种方式主要是因为我想不到其他选择不同enum值的方法,这取决于类别的选择,然后基于enum值选择子类别。
有更好的方法来创建这样的功能吗?我希望能够轻松识别.Category.Subcategory名称,并且如果这段代码可读性强就更好了。
只是为了明确,我想能够选择Category,然后有一个适当的Subcategory选择。
public class Dropdown
{
    public enum Gifts
    {
        GreetingCards,
        VideoGreetings,
        UnusualGifts,
        ArtsAndCrafts,
        HandmadeJewelry,
        GiftsforGeeks,
        PostcardsFrom,
        RecycledCrafts,
        Other
    }
    public enum GraphicsAndDesign 
    {
        CartoonsAndCaricatures,
        LogoDesign,
        Illustration,
        EbookCoversAndPackages,
        WebDesignAndUI,
        PhotographyAndPhotoshopping,
        PresentationDesign,
        FlyersAndBrochures,
        BusinessCards,
        BannersAndHeaders,
        Architecture,
        LandingPages,
        Other
    }
}

1
你正在阅读什么内容,为什么它说这不是个好注意?在大多数情况下,枚举类型不应嵌套在类中;它们应该在顶层,但这似乎是一个合适的上下文。但在大多数情况下,通过父类型一直访问一个枚举类型非常繁琐。如果在某些情况下有益处,那就没问题。 - Servy
你确定不需要一个数据库吗? - acfrancis
如果这些枚举只在Dropdown类中使用,那么你目前所做的就没有任何问题。 - Code Maverick
@Scott StackOverflow的用户给出了几个原因,其中之一是类嵌套不是一个好主意。我只是对替代方案感到好奇。数据库似乎有点过度kill... - Nick Bull
1个回答

4
创建一个不能被外部继承的类,给它添加几个内部类,每个内部类都继承自该类。然后为要表示的每个值添加静态只读变量:
public class Dropdown
{
    private string value;

    //prevent external inheritance
    private Dropdown(string value)
    {
        this.value = value;
    }

    public class Gifts : Dropdown
    {
        //prevent external inheritance
        private Gifts(string value) : base(value) { }

        public static readonly Dropdown GreetingCards =
            new Gifts("GreetingCards");
        public static readonly Dropdown VideoGreetings =
            new Gifts("VideoGreetings");
        public static readonly Dropdown UnusualGifts =
            new Gifts("UnusualGifts");
        public static readonly Dropdown ArtsAndCrafts =
            new Gifts("ArtsAndCrafts");
    }
    public class GraphicsAndDesign : Dropdown
    {
        //prevent external inheritance
        private GraphicsAndDesign(string value) : base(value) { }

        public static readonly Dropdown CartoonsAndCaricatures =
            new GraphicsAndDesign("CartoonsAndCaricatures");
        public static readonly Dropdown LogoDesign =
            new GraphicsAndDesign("LogoDesign");
        public static readonly Dropdown Illustration =
            new GraphicsAndDesign("Illustration");
    }

    public override string ToString()
    {
        return value;
    }
}

在这种情况下,每个值实际上都是Dropdown类型的实例,因此您可以将一个参数传递给接收Dropdown实例的方法。对于枚举类型,无法指定“我要接受Dropdown类中声明的任何枚举”这样的语句。
以下是示例用法:
public static void UseDropdown(Dropdown type)
{
    if (type is Dropdown.Gifts)
    {
        if (type == Dropdown.Gifts.GreetingCards)
        {
            DoStuff();

        }
    }
    else if (type is Dropdown.GraphicsAndDesign)
    {
    }
}

您还可以设置一个参数,接受类型为GiftsGraphicsAndDesign的对象,如果您只想在某些情况下使子类型有效。
不幸的是,使用这种解决方案没有好的方法来switch下拉框的值;您必须使用if/else if链来检查值。
实例字符串值的使用可能不是必需的(请参见第一个版本,其中没有它),但能够拥有有意义的字符串值(或其他类型的值;您可以将整数、字节或任何东西与每个枚举值关联起来)非常有帮助。
如果未被覆盖,EqualsGetHashCode实现应该是有意义的。
如果项目应该以某种逻辑顺序排序,例如真正的枚举,则可以实现IComparable

比我的解决方案好多了 +1。我在考虑删除我的解决方案 ;-( - Harrison
不得不说,这也非常优雅。非常感谢,我更喜欢这个! - Nick Bull
小问题,这个语法是有效的代码,因为它继承了 DropdownDropdown.Gifts.GraphicsAndDesign.Gifts.GraphicsAndDesign 等。 - Nick Bull

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接