Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternative to nesting enums

Tags:

c#

enums

I'm trying to create several enums as such, that gives the syntax of Dropdown.Category.Subcategory. However, I have been reading that this isn't such a good idea. My choice for this was mostly because I couldn't think of any other way to select different enum values depending on the choice of the category, and then the choice of the subcategory is subject to the selected enum based on the enum values.

Is there a better way to create such functionality? I would prefer to be able to easily identify both the .Category and .Subcategory names, and it would be a bonus if this code was readable.

Just to make it clear, I want to be able to choose the Category, then have an appropriate Subcategory selection.

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
    }
}
like image 963
Nick Bull Avatar asked Oct 03 '22 15:10

Nick Bull


1 Answers

Create a class that cannot be inherited from externally, give it several inner classes, each extending from it. Then add static read only variables for each of the values that you want to represent:

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;
    }
}

In this case every single value is actually an instance of type Dropdown, so you could have, say, a parameter to a method that accepts a Dropdown instance. With enums there is no way to say, "I want to accept any of the enums declared in the Dropdown class."

Here is some example usage:

public static void UseDropdown(Dropdown type)
{
    if (type is Dropdown.Gifts)
    {
        if (type == Dropdown.Gifts.GreetingCards)
        {
            DoStuff();

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

You could also have a parameter that accepts an object of type Gifts or GraphicsAndDesign, if you only want a sub-type to be valid in some context.

Sadly, using this solution there's no good way to switch on a dropdown value; you have to just use if/else if chains to check the values.

The use of an instance string value may not be required (see the first revision for a version without it) but it can be very helpful to be able to have a meaningful string value (or other kind of value; you can associate an integer, a byte, or whatever with each enumeration value).

The Equals and GetHashCode implementations should be meaningful if left without being overridden.

You can implement IComparable if the items should be logically ordered somehow, like real enums.

like image 50
Servy Avatar answered Oct 07 '22 19:10

Servy