If I have a C# enum where two objects map to the same integral value, is there any possible way to get each unique Enum
object? Every method I have tried returns only one of the objects - which is likely the first occurrence of the value.
Let's say I have the following enum defined where two objects map to the same integral value for some reason.
public enum Testing
{
[Description("This is Value1")]
[Display(Name = "Value 1")]
Value1 = 0,
[Description("This is Value2")]
[Display(Name = "Value 2")]
Value2 = 1,
[Description("This is Value3")]
[Display(Name = "Value 3")]
Value3 = 2,
[Description("This is Value4")]
[Display(Name = "Value 4")]
Value4 = 0
}
In this case, by some criteria I need Value1
and Value4
to both map to the integral value 0. Functionality the two values will result in identical behavior in the application. The reasoning behind why these two options exists is not necessarily relevant, but let's say for example I want it to be extremely clear to the user that Value1 and Value4 are both mapping to 0 even though they are not necessarily the same option.
I then want to dynamically at runtime load the enum objects from the Testing
type. With enums where two options do not map to the same integral value there are plenty of ways to do this. Using Enum.GetValues()
, Enum.GetNames
, using reflection to get a FieldInfo[]
and then iterating each and calling FieldInfo.GetValue()
. These all work just fine normally... but when two Enum objects map to the same integral value, usage of any methods which give back the Enum object will return the same object for both Value1
and Value4
- likely Value1
.
However, in this case I have set specific attributes on each of the objects. I want to load the objects in a manner that allows me to utilize those attributes during runtime. Perhaps I want to show each option in a pull-down and want to use the name in the Display
attribute to give more user-friendly strings, or be able to provide an additional lengthy description in the tooltip of each option.
I have tried the following methods to no avail, they all result in giving back the Value1
object for Value4
which inevitably results in accessing the custom attributes for Value1
and NOT Value4
.
foreach (Enum value in Enum.GetValues(type))
{
// value for Value4 is Value1...
}
foreach (string name in Enum.GetNames(type))
{
Enum value = (Enum)Enum.Parse(type, name);
// value for Value4 is Value1...
}
foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.Public | BindingFlags.Static))
{
Enum value = (Enum)fieldInfo.GetValue(null);
// value for Value4 is Value1...
// fieldInfo DOES have the custom attributes for Value4 and DOES have the original name Value4
}
Is there any possible way to retain the original enum object for Value4
in C#? I could technically store the FieldInfo
objects, but I would rather (and need to) store the Enum object. I'm quite surprised that not even iterating the field infos through reflection where I definitely do have the Value4
field doesn't return that object.
What you are asking for is not possible. An example program can quickly demonstrate the problem here:
using System;
public enum ExampleEnum
{
SomeValue = 1,
AliasValue = 1
}
public class Program
{
public static void Main()
{
var x = ExampleEnum.AliasValue;
Console.WriteLine(x.ToString());
}
}
You would naturally expect this program to write 'AliasValue' to the console, but instead you see 'SomeValue'. The reason for this is easy enough to understand - enums are implemented as integers behind the scenes. When going from an integer back to the Enum member, C# will just pick the first member that has the corresponding value. C# only preserves the integer value, and if two enum members have the same value then they should be assumed to have the same behaviour too.
In this case, by some criteria I need Value1 and Value4 to both map to the integral value 0. Functionality the two values will result in identical behavior in the application. The reasoning behind why these two options exists is not necessarily relevant, but let's say for example I want it to be extremely clear to the user that Value1 and Value4 are both mapping to 0 even though they are not necessarily the same option.
I would suggest you reconsider this approach. If there is no difference in behaviour, then it should not matter if the label gets 'auto-corrected' to the first option. If it does matter, then it sounds like there is a difference and they should not have the same value.
Since there's still some confusion, I'll add more to my example. You aren't converting between integer and enum yourself, but C# is doing something like that behind the scenes. It might help you to assume 'Enum' is just syntactic suger for a wrapper around the 'integer' type, and each member is converted into a 'const int' field:
public record struct ExampleEnum(int value)
{
public static readonly ExampleEnum SomeValue = new(1);
public static readonly ExampleEnum AliasValue = new(1);
public string ToString() => value switch =>
{
1 => "SomeValue",
_ => value.ToString(),
};
}
public class Program
{
public static void Main()
{
var x = ExampleEnum.AliasValue;
Console.WriteLine(x.ToString());
}
}
*This is not exactly what happens behind the scenes, but it is a close approximation