Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested Enum and Property Naming Conflicts

Tags:

c#

.net

enums

There are some related questions here and here, but they didn't really give me satisfactory answers. The problem is that enums nested in a class in C# cannot have the same name as a property of the class. My example:

public class Card
{
    public enum Suit
    {
        Clubs,
        Diamonds,
        Spades,
        Hearts
    }

    public enum Rank
    {
        Two,
        Three,
        ...
        King,
        Ace
    }

    public Suit Suit { get; private set; }
    public Rank Rank { get; private set; }
    ...
}

There are a few options to hack around this, but they don't seem right to me.

I could move the enums outside the class, but then you would just say Suit instead of Card.Suit, which seems wrong to me. What is a Suit outside the context of a Card?

I could move them outside the class and change them to something like CardSuit and CardRank, but then I'd feel like I'm baking context information into the name of the enum, when that should be handled by a class or namespace name.

I could change the names of the enums to Suits and Ranks, but this violates Microsoft's naming guidelines. And it just doesn't feel right.

I could change the property names. But to what? It feels intuitively right to me to want to say Suit = Card.Suit.Spades.

I could move the enums into a separate static class called CardInfo containing only these enums. If I can't come up with anything else, I think this is the best option.

So I'm wondering what other people have done in similar situations. It would also be nice to know why this is disallowed. Maybe Eric Lippert or someone could chime in on the decision to forbid it? It seems like it only creates ambiguity within the class, and this could be resolved by forcing the use of this.Suit for the property name. (Similar to disambiguating between locals and members.) I assume this was left out due to the "every feature starts with -100 points" thing, but I would be curious about discussions around this.

like image 553
Sean Devlin Avatar asked Feb 13 '10 15:02

Sean Devlin


4 Answers

It would also be nice to know why this is disallowed. Maybe Eric Lippert or someone could chime in on the decision to forbid it?

The point of the rule is to ensure that there is no ambiguity within the class when looking up a name. Certain regions of code are designated as defining a 'declaration space'. The fundamental rule of declaration spaces is no two things declared in the same declaration space have the same name (except for methods, which must differ by signature, not name.)

Making exceptions to this rule just makes things more confusing, not less confusing. I agree that it is vexing that you cannot have a property and an enum of the same name declared in the same declaration space, but once you start making exceptions then it just gets to be a mess. It's usually a nice property that a name uniquely identifies a method group, type parameter, property, and so on.

Note that this rule applies to things declared in a declaration space, not things used in a declaration space. It is perfectly legal to say "public Suit Suit { get; set; }" provided that the type Suit is not declared in the same declaration space as the property. When someone says "Suit.X", figuring out whether X is on the type (that is, X is a static member) or the property (that is, X is an instance member) is a bit tricky. See my article on how we do that for details:

http://blogs.msdn.com/ericlippert/archive/2009/07/06/color-color.aspx

like image 200
Eric Lippert Avatar answered Nov 17 '22 18:11

Eric Lippert


I prefer to name enums using a noun followed by Options. In your case:

SuitOptions
RankOptions

After all, the enum is just a set of possible options, right?

You will have then:

myCard.Suit = Card.SuitOptions.Clubs;

Which in my opinion makes sense and you are still able to know when viewing the text whether is then enum or property.

like image 31
Victor Hurdugaci Avatar answered Nov 17 '22 18:11

Victor Hurdugaci


I would agree with moving the enum definition to a separate place. Currently, the enums are only visible through card, so if you wanted to check for an ace, you would have to do

if (card.CardSuit == Card.Suit.Ace) { }  //need different name for Suit field

Where if you moved it to a separate definition, you could do this if you made it global:

if (card.Suit == Suit.Ace) { } //no naming clashes, easier to read
like image 3
Gordon Gustafson Avatar answered Nov 17 '22 19:11

Gordon Gustafson


It't interesting to see that while the Microsoft Naming Guidelines say you should use a singular name for most enums and plural names for bit fields, the code sample for the enum keyword does use a plural name!

enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
like image 3
comecme Avatar answered Nov 17 '22 18:11

comecme