Code quality, part III: Manually number your enums
When using enumerations, .NET languages automatically assign the numeric values for your enums. For example:
public enum MyColor { Red, Green, Blue }
This yields an enum with the numeric representation of Red = 0, Green = 1, Blue = 2. All this is fine – the numeric versions don't really matter normally. But one thing you should realize is that external assemblies referring to this enum do not get the symbolic names compiled in, but rather the numeric values. Now, if you have A.DLL defining that enumeration and B.DLL that calls a method in A.DLL (say, "SetColor(MyColor)") with something like ClassFromA.SetColor(MyColor.Blue)
doesn't get the name "Blue" embedded into its binary version, but just rather "SetColor(2)".
Now go and change A's enum to have values of { Red, Mauve, Green, Blue }
. The enum gets numbered from 0 (Red) to 3 (Blue). Everything works fine within A, but unless B is recompiled from source with references to the new version of A, the SetColor call looks like it actually had the parameter of MyColor.Green
when it arrives in A.DLL. This is an extremely nasty way of introducing hard-to-find bugs in your code.
Thus, my recommendation: Always manually number all enumerations that have scope outside the defining compilation unit. An easier approach is to just always add the new values to the end of the enumeration, but it won't allow you to remove values from the enum unless you add more manual numbering. I prefer manual numbering even though you have to be careful to keep the numbers unique, as it allows you to sort the enumeration definition in any way without affecting the actual result. So here's an example:
public enum MyColor { Red = 1, Green = 2, Blue = 3 }
If you wish to have them sorted by name in your definition code, go for it:
public enum MyColor { Blue = 3, Green = 2, Red = 1 }
The enumeration values should be treated as one-time-identifiers – once they're assigned to a value and a DLL version is used for compilation of other libraries, the semantics of an enum value shouldn't be changed. So you shouldn't remove Green and reuse the numeric value 2 later on – it will cause the problem identified above. Leave gaps in the numbering and always use a new value for new items.
Also note that most solutions regarding enum value serialization (saving custom configuration files, calling external services with enum-type params etc.) have the same effects than the external-DLL-scenario. So, even if your enum only had scope inside one executable, you may be surprised when loading a config file from an older version of the software that had enum values stored in it. Be careful out there!
January 16, 2005
В· Jouni Heikniemi В· Comments Closed
Posted in: .NET