Jaa


C# : Where do you define an enum

Frequently while designing classes that have methods which accept enums as parameters, a common question arrises on where to define the enum. Whether to define it inside the class or in the same level as the class.

Lets consider a class Folder which has a method List. It accepts a enum Filter and based on it prints the name of all files or directories in the Folder. We can define the enum at the same level as the Folder as below

 enum Filter{    File,    Dir}class Folder{    public Folder(string path) { /* ... */ }    public void List(Filter filter) { /* ... */ }}Folder folder = new Folder("c:\");folder.List(Filter.File);

Or define it inside the Folder class as in

 class Folder{    public enum Filter    {        File,        Dir    }    public Folder(string path) { /* ... */ }    public void List(Filter filter) { /* ... */ }} Folder folder = new Folder(@"c:\");folder.List(Folder. Filter.File);

I think that the first approach is much simpler because otherwise you have to continually type in the complete scope of the enum as Folder. Filter . This soon becomes painfull. I first had a little difficulty understanding why do people still do this. Then I figured out that there are a lot of C++ programmers who have migrated to C# and in un-managed C++ the second approach is the way to go. Lets see why

The issue with C++

If we use the same code in C++ as in the first approach then we get the following

 /*  1 */ namespace MyNameSpace/*  2 */ {/*  3 */     enum Filter/*  4 */     {/*  5 */         File,/*  6 */         Dir/*  7 */     };/*  8 */ /*  9 */     //char File[] = "c:\\foo\\bar";/* 10 */     class Folder/* 11 */     {/* 12 */     public:/* 13 */         Folder(char* path) { /* ... */ }/* 14 */         void List(Filter filter) { /* ... */ }/* 15 */     };/* 17 */ }

According to C++ spec the enum constant File and Dir is raised to the same scope as that of Filter. So effectively nowhere in the whole namespace of MyNameSpace can variables of name File or Dir can be defined. So if you uncomment the 9th line then compilation will fail indicating redeclaration of variable File.

So defining enums at the level of classes have serious consequence of namespace pollution. So C++ programmers generally put the enum declaration inside the class definition. This requires the client program to use scope resolution a bit too much even then this is worth the extra typing.

However, in C# since this is a non-issue the enum must be declared at the same level as the class.

Comments

  • Anonymous
    October 24, 2005
    "...MUST be decalred at the same level as the class."

    That's a bold statement.

    First off, MUST is clearly the wrong word to use here. Obviously, one can legally decalre the enum inside of the class. So perhaps the word SHOULD is more appropriate.

    But, even then, I feel your logic is wrong. Your main complaint against embedding the enum inside of the class is that it will take too long to type. Given how verbose C# tends to be, this is not really a sensible argument. In VS, CTRL+SPACE is your friend.

    Logically, I feel placing the enum inside of the class is far more correct. Take your example: what is a MyNameSpace.Filter? Where does it apply? I guess it's a filter for your namespace? It's impossible to tell, especially if your namespace grows to contain dozens of classes.

    Now consider MyNameSpace.Folder.Filter -- it is, in my mind, far more intuitive that Filter applies in some way, shape, or form to the Folder class. Indeed, another class can be added to the namespace with its own concept of filter, one of whose members may be 'File'. Just because you've introduced a new class into the namespace doesn't give you the right to pollute that namespace with various 'helper' types. If you are developing as part of a large development team, your style is, well, rude.

    Even in C#, the enum SHOULD be declared within the class.

  • Anonymous
    October 24, 2005
    While my first instinct is to put the enum at the same level as the class, I tend to think about who will use the enum and where it makes sense to use it.

    If there are many classes an operations that will use the enum, it goes in the namespace.
    If I'm sure the enum is used only by the one class, then I might nest it.
    If it can be used directly by consumers of my library, I probably won't nest it.

    Having an enum called "Filter" all by itself might be missleading, a clearer name is needed if it isn't nested. FileSystemThings {File,Dir}



  • Anonymous
    October 24, 2005
    Another reason clearly defined scope. While a namespace shouldn't really contain multiple definitions for an enum, I'm sure most programmers have encounter the Project.Util catch all.


    Even when namespaced correctly though, think of instancs where you might have say a Logger, with a Level enum. You use that Logger to log errors and exceptions in say a Equation Building UI. For this UI, you need to be able to notify the user of incorrect inputs, you you create a UserNotifier, and a Level enum to indicate if its a warning, error, or just informational. Since the UserNotifier and Logger are in different NameSpaces, there's no real issue.

    But for an enforced code readability its nice to see Logger.Level vs. UserNotifier.Level Sure it should be intuitive, what constant was being passed by the method being called, but it just reads nicer, when scanning code to interpret its intent.

  • Anonymous
    October 24, 2005
    I've struggled with this myself and I did not come from C++. Depending on how the enum is used in the code, I still use both approaches. I use the external approach for enums that are shared between classes or clearly unique and belonging to one class. I use the nested approach when the relationship between the enum and its class is not as clear.

    The problem in your example is that Filter isn't very descriptive. So if you had another class, say File, in the same namespace that also needs a filter, you need to rename Filter into something that logically links it with the class it belongs to.

    Now you have FolderFilter and FileFilter as your enums. And at that point, I can't really see how that is better than having Folder.Filter and File.Filter? At least the latter approach clearly ties the enum to the class that uses it.

  • Anonymous
    October 24, 2005
    The comment has been removed

  • Anonymous
    October 24, 2005
    ToddM, I agree "must" is a strong word I'll downgrade it to "should".

    But I stick to this "should".

    I have time again seen that people point to intellisense and other editor features to justify or nullify arguments. But a editor feature can never justify design decisions. Not everyone uses VS editor. Moreover a lot of people have build systems that do not use solutions and rely on make files (nmake) or "sources" "dirs" files (NTBuild). Since there is no sln/proj files for the VS editor to use, intellisense do not work and users open CS files individually to edit. This is not a corner case situation and some teams even in MS uses this approach.

    My post is in the context of class libraries (I should have clarified this). I think in terms of class library design enums should be at the level of the classes. Class libraries commonly have proper namespaces and so the enums do not globally pollute the namespace. Moreover since classes in one class library tend to do similiar things, in the long run typically these enums start getting used in more than one place. Nesting them inside one class severely hinders this sharing as you cannot simply rip them out from inside one class and not break some clients. Additionally due to this sharing some enums will be at the level of the classes and some nested inside classes. This will make the system unintuitive...

  • Anonymous
    October 25, 2005
    The comment has been removed

  • Anonymous
    April 03, 2007
    The comment has been removed

  • Anonymous
    October 16, 2008
    If you look at examples in .NET itself you will see cases where the enum is declared on the same level as the class that uses it. Take FileStream in System.IO for example. Creating a new instance takes in as a parameter a FileMode value. The emum is not declared inside the FileStream class. I think you will see this a lot. Now, I don't have a definitive answer as to what Microsoft's justification for doing that was but I think it lends credibility to the argument that placing enum declarations at the level of the class is more than fine.

  • Anonymous
    July 07, 2009
    I agree that the enum should go at the same level as the class.  I see this for two reasons. In the Microsoft Class Library Design Guidelines under the conventions for naming properties, it suggests that you consider naming the property with the same name as its type.  If the enum is defined inside the class the compiler will generate an error for a name conflict.  If the enum is defined outside of the class this conflict does not occur. The second reason, is I like for my code to appear as if it belongs in the Framework itself.  If you analyze the namespaces in the object viewer you will be hard pressed to find very many enums inside classes.  Most are at the class level. Just my two cents.  (with the economy the way it is now, only worth 1 cent) -john

  • Anonymous
    July 07, 2009
    Also, I found this discussion at Microsoft's Channel 9.  This question was asked and a couple people replied. They favor defining the enum outside of a class if that enum is going to be referenced and used anywhere outside of a particular class. http://channel9.msdn.com/forums/TechOff/256471-Simple-Archicecture-question/ -john

  • Anonymous
    November 13, 2009
    I find it disheartening that a developer would choose one approach over another based on how much typing they have to do. Have we learned nothing in the last 50 years? Programmers have to make many choices every day between various trade-offs... but how long it takes you to type something should NOT be one of them. The question to ask yourself here is this: what is the least exposure I can give to my enum and still get the job done? Least exposure == most protection from other people accidentally using something you didn't want them to use. Start at the most restrictive scope possible, and if you need to raise the access to the enum further, then move it out in scope one bit at a time until you find the most-restrictive scope that works. But please, PLEASE, for the love of all that is binary, don't pick an approach based on how many characters you have to type.

  • Anonymous
    November 15, 2013
    After taking a course in the Agile Methodology, it seems the reason to keep it outside the class is to prevent method chaining.

  • Anonymous
    January 29, 2014
    Please, please for the love of sanity don't base any decisions on the "wisdom" of Agile methodology.