ToString()
on an enum
value which has multiple corresponding names?Long explanation
I might be going too far here, but I think it's decided by binary search of the sorted values, and so can depend on the parity of the total number of values. You can illustrate this with your last example (RgbColorWithAFirst
and RgbColorWithALast
) by defining another value in both - then you get A
from all the ToString
invocations.
I got here by decompiling mscorlib
(4.0) and noting that eventually we get to a call to Array.BinarySearch
on a sorted array of the declared values. Naturally, the binary search stops as soon as it gets a match, so to get it to switch between two identical values the easiest way is to alter the search tree, by adding an extra value.
Of course, this is an implementation detail and should not be relied on. It seems to me that in your case you would be best served by using DescriptionAttribute
on enum values where you want to be explicit about the display value, and a helper method such as:
public static class EnumExtensions
{
public static string Description(this Enum value)
{
var field = value.GetType().GetField(value.ToString());
var attribute = Attribute.GetCustomAttribute(
field,
typeof (DescriptionAttribute))
as DescriptionAttribute;
return attribute == null ? value.ToString() : attribute.Description;
}
}
The behavior is undefined. Even if you are able to show what the result is for some specific version of .NEt it could change. See the enum.toString documentation, which says:
If multiple enumeration members have the same underlying value and you attempt to retrieve the string representation of an enumeration member's name based on its underlying value, your code should not make any assumptions about which name the method will return. For example, the following enumeration defines two members, Shade.Gray and Shade.Grey, that have the same underlying value.
enum Shade { White = 0, Gray = 1, Grey = 1, Black = 2 }
The following method call attempts to retrieve the name of a member of the Shade enumeration whose underlying value is 1. The method can return either "Gray" or "Grey", and your code should not make any assumptions about which string will be returned.
string shadeName = ((Shade) 1).ToString();
Also see the previous paragraph is documentation, which shows how to retrieve all names
The documentation warns that duplicate values will produce errors.
You have duplicate values and are getting errors - not a surprise.
You are getting the first Equal.
Equal is based solely on value.
You have no control over the order in which the enum is evaluated.
As stated in comment an enum expects unique values for the type.
Enumeration Types (C# Programming Guide)
However, you should not do this because the implicit expectation is that an enum variable will only hold one of the values defined by the enum. To assign an arbitrary value to a variable of an enumeration type is to introduce a high risk for errors.
Apparently you have uncovered one of the high risk errors with a duplicate values for type.
I characterize this error as non deterministic as I consider changing the order but same data the same input given nothing in the spec state of implies enum input is order dependent. OP considers different order as different data. With the OP's assumption would not characterize this a non deterministic. Still fair to characterized it as an error caused by duplicate values for type.
Another reference that implies uniqueness is expected
Enum.GetName
The return is string (not string[]).
Equals is based solely on value.
Enum.Equals
GetName is going to match on the first value.
That is my definition of non-deterministic.
How can you know which you have if have if they are considered equal?
Suspect Microsoft does not enforce uniqueness of enum type values due to overhead.
OP expects that Enum explicitly associates A value with A string (like a KVP) when there is no indication of that type of association.
The documentation explicitly warns against making that assumption.
Where does the documentation indicate Enum is implemented as a set of key value pair, class, or strut?
The results and methods indicate an Enum is a string and value type (other than char) with a loose association.
Possible work around.
A Dictionary does not require unique values.
public enum RgbColor : byte
{
Black,
Red,
Green,
Blue,
White,
Default
}
static void Main(string[] args)
{
Dictionary<RgbColor, Int32> ColorRGB = new Dictionary<RgbColor, int>();
ColorRGB.Add(RgbColor.Black, 0x000000);
ColorRGB.Add(RgbColor.Default, 0x0000ff);
ColorRGB.Add(RgbColor.Blue, 0x0000ff);
ColorRGB.Add(RgbColor.Green, 0x00ff00);
ColorRGB.Add(RgbColor.White, 0xffffff);
Debug.WriteLine(ColorRGB[RgbColor.Blue].ToString("X6"));
Debug.WriteLine(ColorRGB[RgbColor.Default].ToString("X6"));
Debug.WriteLine(ColorRGB[RgbColor.Black].ToString("X6"));
Debug.WriteLine(ColorRGB[RgbColor.White].ToString("X6"));