tags:

views:

295

answers:

2

Hi,

I wonder is there a way to prevent an enum with duplicate keys to compile?

For instance this enum below will compile

public enum EDuplicates
{
    Unique,
    Duplicate = 0,
    Keys = 1,
    Compilation = 1
}

Although this code

Console.WriteLine(EDuplicates.Unique);
Console.WriteLine(EDuplicates.Duplicate);
Console.WriteLine(EDuplicates.Keys);
Console.WriteLine(EDuplicates.Compilation);

Will print

Duplicate
Duplicate
Keys
Keys
+6  A: 

This isn't prohibited by the language specification, so any conformant C# compiler should allow it. You could always adapt the Mono compiler to forbid it - but frankly it would be simpler to write a unit test to scan your assemblies for enums and enforce it that way.

Jon Skeet
I'm probably missing the point here: What is the useful scenario for supporting this? If there are no useful scenarios why would you prefer writing unit tests for this over letting the compiler handle the situation?
Brian Rasmussen
@Brian: To avoid breaking existing code. Backwards compatibility is important, as is conforming with the spec. I can't immediately think of any useful scenarios, but that doesn't mean I would want to break anyone who is using this already.
Jon Skeet
@Brian: It can be useful if you for some reason wish to change the name of an enum value without breaking old code: add a new value with the new name and the same numeric value as the old one, and decorate the old value with the `Obsolete` attribute.
Fredrik Mörk
@Fredrik: Good point. I didn't think of that. Thanks.
Brian Rasmussen
I had discovered this problem (duplicate keys) while writing unit test for semi-autogenerated enums. It was an unpleasant surprise, so I got myself interested is there a way to ensure this somehow. I was thinking of an Attribute or compiler flag or something like that.
zzandy
wouldn't also be useful for providing several alternate names for the same thing? (like "Ace" and "HighestFaceCard"). Or is that an anti-pattern?
moogs
Yes, obviously, the whole build could be set up to break on unit test break so using unit test is quite enough, I have overlooked this before.
zzandy
Another option which some people like is to have a "MinimumValue" and "MaximumValue". I'm not terribly fond of it myself...
Jon Skeet
+1  A: 
public bool ValidateAllDistinct(Type enumType)
{
    return !Enum.GetNames(enumType).All(outerName
        => Enum.GetNames(enumType).Any(innerName
            => innerName == outerName 
                ? true 
                : Enum.Parse(enumType, innerName) != Enum.Parse(enumType, outerName)));
}

I simple test method for your unittest.

AndreasN
This is something like the unit test I had had to write with only difference my is printing duplicate keys.
zzandy