How to get the Enum Index value in C# - c#

In C, enums, internally equates to an integer. Therefore we can treat data types of enum as integer also.
How to achieve the same with C#?

Firstly, there could be two values that you're referring to:
Underlying Value
If you are asking about the underlying value, which could be any of these types: byte, sbyte, short, ushort, int, uint, long or ulong
Then you can simply cast it to it's underlying type. Assuming it's an int, you can do it like this:
int eValue = (int)enumValue;
However, also be aware of each items default value (first item is 0, second is 1 and so on) and the fact that each item could have been assigned a new value, which may not necessarily be in any order particular order! (Credit to #JohnStock for the poke to clarify).
This example assigns each a new value, and show the value returned:
public enum MyEnum
{
MyValue1 = 34,
MyValue2 = 27
}
(int)MyEnum.MyValue2 == 27; // True
Index Value
The above is generally the most commonly required value, and is what your question detail suggests you need, however each value also has an index value (which you refer to in the title). If you require this then please see other answers below for details.

Another way to convert an Enum-Type to an int:
enum E
{
A = 1, /* index 0 */
B = 2, /* index 1 */
C = 4, /* index 2 */
D = 4 /* index 3, duplicate use of 4 */
}
void Main()
{
E e = E.C;
int index = Array.IndexOf(Enum.GetValues(e.GetType()), e);
// index is 2
E f = (E)(Enum.GetValues(e.GetType())).GetValue(index);
// f is E.C
}
More complex but independent from the INT values assigned to the enum values.

By default the underlying type of each element in the enum is integer.
enum Values
{
A,
B,
C
}
You can also specify custom value for each item:
enum Values
{
A = 10,
B = 11,
C = 12
}
int x = (int)Values.A; // x will be 10;
Note: By default, the first enumerator has the value 0.

You can directly cast it:
enum MyMonthEnum { January = 1, February, March, April, May, June, July, August, September, October, November, December };
public static string GetMyMonthName(int MonthIndex)
{
MyMonthEnum MonthName = (MyMonthEnum)MonthIndex;
return MonthName.ToString();
}
For Example:
string MySelectedMonthName=GetMyMonthName(8);
//then MySelectedMonthName value will be August.

Use simple casting:
int value = (int) enum.item;
Refer to enum (C# Reference)

Use a cast:
public enum MyEnum : int {
A = 0,
B = 1,
AB = 2,
}
int val = (int)MyEnum.A;

using System;
public class EnumTest
{
enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};
static void Main()
{
int x = (int)Days.Sun;
int y = (int)Days.Fri;
Console.WriteLine("Sun = {0}", x);
Console.WriteLine("Fri = {0}", y);
}
}

One reason that the designers c# might have chosen to NOT have enums auto convert was to prevent accidentally mixing different enum types...
e.g. this is bad code followed by a good version
enum ParkingLevel { GroundLevel, FirstFloor};
enum ParkingFacing { North, East, South, West }
void Test()
{
var parking = ParkingFacing.North; // NOT A LEVEL
// WHOOPS at least warning in editor/compile on calls
WhichLevel(parking);
// BAD wrong type of index, no warning
var info = ParkinglevelArray[ (int)parking ];
}
// however you can write this, looks complicated
// but avoids using casts every time AND stops miss-use
void Test()
{
ParkingLevelManager levels = new ParkingLevelManager();
// assign info to each level
var parking = ParkingFacing.North;
// Next line wrong mixing type
// but great you get warning in editor or at compile time
var info=levels[parking];
// and.... no cast needed for correct use
var pl = ParkingLevel.GroundLevel;
var infoCorrect=levels[pl];
}
class ParkingLevelInfo { /*...*/ }
class ParkingLevelManager
{
List<ParkingLevelInfo> m_list;
public ParkingLevelInfo this[ParkingLevel x]
{ get{ return m_list[(int)x]; } }}

In answering this question I define 'value' as the value of the enum item, and index as is positional location in the Enum definition (which is sorted by value). The OP's question asks for 'index' and various answer have interpreted this as either 'index' or 'value' (by my definitions). Sometimes the index is equal to numerical value.
No answer has specifically addressed the case of finding the index (not value) where the Enum is an Enum flag.
Enum Flag
{
none = 0 // not a flag, thus index =-1
A = 1 << 0, // index should be 0
B = 1 << 1, // index should be 1
C = 1 << 2, // index should be 2
D = 1 << 3, // index should be 3,
AandB = A | B // index is composite, thus index = -1 indicating undefined
All = -1 //index is composite, thus index = -1 indicating undefined
}
In the case of Flag Enums, the index is simply given by
var index = (int)(Math.Log2((int)flag)); //Shows the maths, but is inefficient
However, the above solution is
(a) Inefficient as pointed out by #phuclv (Math.Log2() is floating point and costly) and
(b) Does not address the Flag.none case, nor any composite flags - flags that are composed of other flags (eg the 'AandB' flag as in my example).
DotNetCore
If using dot net core we can address both a) and b) above as follows:
int setbits = BitOperations.PopCount((uint)flag); //get number of set bits
if (setbits != 1) //Finds ECalFlags.none, and all composite flags
return -1; //undefined index
int index = BitOperations.TrailingZeroCount((uint)flag); //Efficient bit operation
Not DotNetCore
The BitOperations only work in dot net core. See #phuclv answer here for some efficient suggestions https://stackoverflow.com/a/63582586/6630192
#user1027167 answer will not work if composite flags are used, as per my comment on his answer
Thankyou to #phuclv for suggestions on improving efficiency

Related

Union of enum members in C#

Let us say, I have an enum BasicType, which is defined as follows:
public enum ObjectType{
A = 1,
B = 2,
C = 3,
}
The BasicType identifies performs a ternary classification of any Object. Subsequently, I realized that the objects A and B need to be treated in a similar way as compared to C, so I defined another enum ObjectGroupType as follows :
public enum ObjectGroupType
{
AB = 1,
C = 2,
}
With the new enum, I am able to bucket objects of several known types as one. So, when I receive a stream of objects in various types, I actually identify whether they belong to AB or C type. Is there an elegant workaround for this? For instance, will I be able to assign the same enum values for A and B in the ObjectGroupType?:
Edit 1 : I am unable to find the resemblance to the question here
Edit 2 : Thank you Maurice for your constructive inputs -- taking cues from your answer, I came up with this redefined ObjectGroupType.
public enum ObjectGroupType
{
AB = ObjectType.A | ObjectType.B
C = 2,
}
Is this valid?
Essentially, when I process a stream of objects of type AB, I want to ascertain Type A or Type B objects. This is quite similar to a hierarchical two-level decision tree:
object
/ \
AB C
/\
A B
I apologize in advance if I misread your intent, but it almost sounds like you want to allow multiple different enum types to be acted on in your code based on the enum value. The good thing is that you can do that already with bitwise operations and enums.
Given an enum that looks like this:
[Flags]
enum ObjectType
{
A = 1,
B = 2,
C = 4,
D = 8
}
You can set a comparison value that is the bitwise OR of several values:
var allowedValues = ObjectType.A | ObjectType.C;
This works because the values in the enum act like bit fields under the covers.
When you run your code, you do a bitwise AND on the allowedValues variable and the test variable and see if it matches your test variable. If it does, then it is one of the values you want:
if ((test & allowed) == test) ...
Below is a working example using the enum above that shows you how it works.
void Main()
{
var allowed = ObjectType.A | ObjectType.C;
var values = new int [] { 1, 2, 4, 8 };
foreach (var i in values)
{
var test = (ObjectType)i;
if ((test & allowed) == test)
{
Console.WriteLine("Found a match: {0}", test);
}
else
{
Console.WriteLine("No match: {0}", test);
}
}
}
Best of luck!
Edit:
I found the answer of Maurice Reeves very good, I only want to bring some more info:
[Flags]
public enum ObjectType
{
None=0,
A = 1,
B = 2,
C = 4,
D = 8,
E = 16,
AorB=A|B,
BorCorD=B|C|D,
}
By using [Flags] attribute, you can create sets of enum items, which can help you establishing different business rules for each set.
In order to check if and item exist in a set you can do as follow:
public static bool IsAorB(this ObjectType item)
{
return ObjectType.AorB.HasFlag(item);
}
if you want to creat on the fly new set of items, you can do:
var newGroup=ObjectType.A | ObjectType.BorCorD;
if you want to apply some business rule to a set, except an item, you can do:
var newGroupExceptC =newGroup^=ObjectType.C;
Now if you check if element C exist in the set you will get false:
bool exist=newGroupExceptC.HasFlag(ObjectType.C) // =false
more info you can find here
You might use a int instead of an enum, use values that don't overlap when combined (i.e. values whose binary representation has only one bit on) and then perform a mask operation on the ObjectType of a parameter to determine if it is AB:
class SomeClass
{
public static class ObjectType
{
public const int A = 1;
public const int B = 2;
public const int C = 4;
public const int D = 8;
}
public int MyType;
public string Title;
static void Main(string[] args)
{
List<SomeClass> list = new List<SomeClass>()
{
new SomeClass() {Title ="I am of type A", MyType = ObjectType.A }
,new SomeClass() {Title ="I am of type B", MyType = ObjectType.B }
,new SomeClass() {Title ="I am of type AB", MyType = ObjectType.A | ObjectType.B }
};
list.ForEach(p => { if (p.MyType == (ObjectType.A | ObjectType.B)) Console.WriteLine(p.Title); });
}
}
The downside of this approach is losing strong-typing of Object Type, i.e. you can assign any value not just those you define in the ObjectType.

How to get enum order?

If I have enum:
public enum ImportState : byte
{
None = 0,
ImportedWithChanges = 44,
AwaitingApproval = 45,
Removing = 66,
Revalidating = 99,
};
How to get enum order?
For example:
GetOrder(ImportState.None)
Should return 1(first in order)
GetOrder(ImportState.AwaitingApproval )
Should return 3 (third in order)
here is the missing method GetOrder
public static int GetOrder(ImportState State)
{
return Enum.GetValues(typeof(ImportState)).Cast<ImportState>().Select((x, i) => new { item = x, index = i }).Single(x => x.item == State).index;
}
As other noticed, Enum.GetValues() returns the values of an enum sorted by value. Perhaps this isn't what you wanted... So, using a little reflection:
public class EnumOrder<TEnum> where TEnum : struct
{
private static readonly TEnum[] Values;
static EnumOrder()
{
var fields = typeof(Values).GetFields(BindingFlags.Static | BindingFlags.Public);
Values = Array.ConvertAll(fields, x => (TEnum)x.GetValue(null));
}
public static int IndexOf(TEnum value)
{
return Array.IndexOf(Values, value);
}
}
Example of use:
public enum Values
{
Foo = 10,
Bar = 1
}
int ix = EnumOrder<Values>.IndexOf(Values.Bar); // 1
Note that the C# specifications aren't clear if the "source code" ordering of an enum is maintained in the compiled program... At this time the C# compiler seems to maintain it, but there is no guarantee in the future...
The only two references I've found are:
Forward declarations are never needed in C# because, with very few exceptions, declaration order is insignificant
and
Declaration order for enum member declarations (§14.3) is significant when constant-expression values are omitted.
So as written, for the example I gave, the ordering is undefined and depends on the C# compiler!
Enumerating the enum values, casting to an IEnumerable, converting to a List. This it is a simple matter of using IndexOf().
Note that for this to work, the enum must be declared in increasing order.
namespace ConsoleApplication1
{
using System;
using System.Linq;
class Program
{
public enum ImportState : byte
{
None = 0,
ImportedWithChanges = 44,
AwaitingApproval = 45,
Removing = 66,
Revalidating = 99,
}
static void Main(string[] args)
{
Console.WriteLine(GetOrder(ImportState.None));
Console.WriteLine(GetOrder(ImportState.AwaitingApproval));
}
public static int GetOrder(ImportState state)
{
var enumValues = Enum.GetValues(typeof(ImportState)).Cast<ImportState>().ToList();
return enumValues.IndexOf(state) + 1; // +1 as the IndexOf() is zero-based
}
}
}
1
3
Press any key to continue . . .
Sth. like this?
int i = 0;
foreach (ImportState state in Enum.GetValues(typeof(ImportState)))
{
i++;
if (state == myState) return i;
}
However there is no real use for this, as enums do not provide an indexed enumeration in themselfes. They represent a value which is more what you´re probably after.
You can use this LINQ query:
int position = Enum.GetValues(typeof(ImportState)).Cast<ImportState>()
//.OrderBy(impState => (int)impState)
.TakeWhile(impState => impState != ImportState.None)
.Count() + 1;
It orders by the int-value of the enum-value, then it takes all until the searched value and counts them. I have omitted the OrderBy since Enum.GetValues automatically returns the order according to their int-value.
MSDN:
The elements of the array are sorted by the binary values of the
enumeration constants
Instead of using the order, you would be better to make better use of the flags. Consider the following
public enum ImportState : byte
{
None = 0,
ImportedWithChanges = 2,
AwaitingApproval = 4,
Removing = 6,
Revalidating = 8,
};
(double)state / Enum.GetValues(typeof(ImportState)).Cast<byte>().Max()
Example
Enums don't really have any sense of ordering, using the above probably still isn't perfect but it doesn't involve a made up order.
What about this Solution?
var result = from r in Enum.GetValues<ImportState>()
let expression =
r == ImportState.Revalidating
? 0
: r == ImportState.AwaitingApproval
? 1
: r == ImportState.Removing
? 2
: r == ImportState.ImportedWithChanges
? 3
: 4
orderby expression ascending
select r.ToString();
Console.WriteLine(string.Join(", ", result));
Output: Revalidating, AwaitingApproval, Removing, ImportedWithChanges, None

How to get numeric position of an enum in its definition list?

I need to get the numeric position of an enum in its definition.
Consider the following enum - it is used for bit fields but the status names
would be useful if they had the values on the right that I have commented.
[Flags]
public enum StatusFlags
{
None = 0, // 0 -- these commented indexes are the numbers I also would like
Untested = 1, // 1 to associate with the enum names.
Passed_Programming = 2, // 2
Failed_Programming = 4, // 3
// ... many more
}
I have created a static method as follows, which works for what I want.
public static int GetStatusID(this StatusFlags flag)
{
int i = 0;
foreach (StatusFlags val in Enum.GetValues(typeof(StatusFlags)))
{
if (flag == val) break;
i++;
}
return i;
}
It is used like this:
StatusFlags f = StatusFlags.Failed_Programming;
// I want the position i.e value of 3 not the value the enum is associated with i.e 4
int Index = f.GetStatusID();
Is there is a better way to do this?
How about using attributes on your enum? Something like this:
[Flags]
public enum StatusFlags
{
[Index=0]
None = 0,
[Index=1]
Untested = 1,
[Index=2]
Passed_Programming = 2,
[Index=3]
Failed_Programming = 4,
// ... many more
}
Then you can the index value of your enum like this:
var type = typeof(StatusFlags);
var statusFlag = type.GetMember(StatusFlags.Untested.ToString());
var attributes = statusFlag [0].GetCustomAttributes(typeof(IndexAttribute),false);
var index = int.Parse(((IndexAttribute)attributes[0]).Index); //if you need an int value
A deleted answer here suggested something that resembled
public static int GetStatusID(this StatusFlags flag)
{
return Array.IndexOf(Enum.GetValues(typeof(StatusFlags)), flag);
}
and was just missing the syntactical point that IndexOf is a static function in the Array class, not an extension method. I like it though for brevity.
You could do this:
public static int GetStatusID(this StatusFlags flag)
{
return
Enum
.GetValues(typeof(StatusFlags))
.Cast<StatusFlags>()
.Select((f, n) => new { f, n })
.Where(fn => fn.f == flag)
.Select(fn => fn.n)
.DefaultIfEmpty(0)
.First();
}
How about just using math? He says the flags go up in powers of 2
int GetStatusID(this StatusFlags flag)
{
if (((int)flag) == 0) return 0;
return (Math.Log((double)flag) / Math.Log(2D)) + 1;
}
If each flag has only 1 bit set like that then the index is just Math.Log2((int)flag) + 1. However Math.Log2 is a floating-point operation and is very slow so don't use it
If you're using .NET Core then there are BitOperations.Log2 and BitOperations.TrailingZeroCount which map directly to hardware instructions like TZCNT/BSF in x86 or CLZ in ARM, hence are much more efficient and the result is like this
public static int GetStatusID(this StatusFlags flag)
{
if ((int)flag == 0)
return 0;
return BitOperations.Log2((int)flag);
// or return BitOperations.TrailingZeroCount((int)flag) + 1;
}
If you're using an older .NET framework then calculate see the way to calculate integer log2 quickly in these questions
What's the quickest way to compute log2 of an integer in C#?
Fastest implementation of log2(int) and log2(float)
Fast way of finding most and least significant bit set in a 64-bit integer

How do I get the assigned values for enum members?

The following code returns One, Two, Three, where I expect GetNames to do that and GetValues to return 2, 5, 10:
enum Nums
{
One = 2,
Two = 5,
Three = 10
}
class Program
{
static void Main()
{
var vals = Enum.GetValues(typeof(Nums));
}
}
What is up here? How do I get the values 2, 5, 10 from the type Nums?
cast it to an int like this:
int value = (int)Num;
You need to cast it to an int:
int val = (int)Nums.One;
Or to answer your question for getting all of the items in the enum:
IEnumerable<int> values = Enum.GetValues(typeof(Nums)).Cast<int>();
You can do it like this:
int[] vals = Enum
.GetValues(typeof(Nums)) // Thus far, this is your code
.Cast<int>() // Cast individual elements to int
.ToArray(); // Convert the result to array
Here is a demo on ideone.
I haven't fully wrapped my head around C# Enums yet, but the Enum.GetValues documentation has an example that shows that casting has some very interesting and powerful effects on them. http://msdn.microsoft.com/en-us/library/system.enum.getvalues(v=vs.110).aspx
using System;
enum SignMagnitude { Negative = -1, Zero = 0, Positive = 1 };
public class Example
{
public static void Main()
{
foreach (var value in Enum.GetValues(typeof(SignMagnitude))) {
Console.WriteLine("{0,3} 0x{0:X8} {1}",
(int) value, ((SignMagnitude) value));
} }
}
// The example displays the following output:
// 0 0x00000000 Zero
// 1 0x00000001 Positive
// -1 0xFFFFFFFF Negative

How to identify given int value belongs to which enum

Hi before going to direct problem let me show my code :
//Definition of enum
public enum LogType
{
Warning = -2,
Error = -1,
Info = 0,
EruCtorDtor = 1,
Notifications = 2,
CommunicationWithAOT = 4,
ExecutedOrder = 8,
ERUInfo = 16,
DebugLog = 32,
}
//Use of enum
CurrentLogFlagSettings = nLogFlag;
LogFlagMap = new SortedDictionary<LogType, int>();
ulong mask = 1;
while(mask <= nLogFlag)
{
if ((nLogFlag & mask) == mask)
{
LogType type = (LogType)mask; //Step 1
string val = type.ToString(); //Step 2
//Processing the value
LogFlagMap.Add(type, tempVal)
LogMsg(val + " added", type);
}
mask <<= 1;
}
What I want is : Process step2 only after step1 has produced valid value. I mean value should be between range defined in enum definition. Otherwise I dont want to process it.
for e.g.
case 1 - Lets say mask value is 32,
its defined in enum. So type is
getting value DebugLog and so it
type.ToString() (i.e. "DebugLog"),
this is a valid case.
case 2- Lets
say mask value is 128 and its not
defined in enum, in this case I dont
want to process anything on 128
value. But what is happening its
geting value 128 in type and
type.ToString() is converting it
into 128. I dont want this, I want
to make sure whether 128 belongs to
enum values or not.
I want to prevent 2nd case to be executed. Is there any solution for my problem?
Please let me know if more details are needed.
You could use Enum.IsDefined, like so:
int value = 128;
Console.WriteLine(Enum.IsDefined(typeof(LogType), value)); // will print out False
Firstly, let me seriously apologise, Ive had like no sleep, so if I missed the point a little. Please, just ignore me.
You can enumerate your LogType with Enum.GetValues(typeof(LogType))), so you could step through and check a value against it. I had some code, but, I couldnt promise it compiled.
Bool isValid(int i)
{
foreach (LogType l in Enum.GetValues(typeof(LogType)))
{
if ((int)l == i) return true;
}
return false;
}
You can also use Enum.GetValues(typeof(LogType)) to get all the possible values for your enum and do what you want through that.
i.e.
var values = Enum.GetValues(typeof (LogType));
foreach (LogType type in values)
{
if (((int)type & nLogMask) == (int)type)
{
//value is valid, process the value
}
}
One addition to your code could be the addition of the [Flags] attribute to you enum, this then makes it clear that the enum values are for bitwise operations
e.g.
[Flags]
public enum LogType
{
Warning = -2,
Error = -1,
Info = 0,
EruCtorDtor = 1,
Notifications = 2,
CommunicationWithAOT = 4,
ExecutedOrder = 8,
ERUInfo = 16,
DebugLog = 32,
}
although to do this, you would need to change the values such that the Warning and Error take the top 2 bits of the enum value (assuming this is still necessary).
The c# Enum class also has the method GetName(). This might provide a nice and easy manner to retrieve the name of the value set
e.g.
Enum.GetName( typeof(LogType), 4 ); // result = CommunicationWithAOT
I have a library called Unconstrained Melody which allows you to express all of this in a type-safe generic way and avoids boxing too. Personally I prefer that over using Enum.IsDefined, but obviously that doesn't involve learning an extra library.
It's probably not worth using Unconstrained Melody if this is the only thing you need to do with your enum, but if you've got other similar operations, you may wish to consider it.

Categories

Resources