Getting the max value of an enum - c#

How do you get the max value of an enum?

Enum.GetValues() seems to return the values in order, so you can do something like this:
// given this enum:
public enum Foo
{
Fizz = 3,
Bar = 1,
Bang = 2
}
// this gets Fizz
var lastFoo = Enum.GetValues(typeof(Foo)).Cast<Foo>().Last();
Edit
For those not willing to read through the comments: You can also do it this way:
var lastFoo = Enum.GetValues(typeof(Foo)).Cast<Foo>().Max();
... which will work when some of your enum values are negative.

I agree with Matt's answer. If you need just min and max int values, then you can do it as follows.
Maximum:
Enum.GetValues(typeof(Foo)).Cast<int>().Max();
Minimum:
Enum.GetValues(typeof(Foo)).Cast<int>().Min();

According to Matt Hamilton's answer, I thought on creating an Extension method for it.
Since ValueType is not accepted as a generic type parameter constraint, I didn't find a better way to restrict T to Enum but the following.
Any ideas would be really appreciated.
PS. please ignore my VB implicitness, I love using VB in this way, that's the strength of VB and that's why I love VB.
Howeva, here it is:
C#:
static void Main(string[] args)
{
MyEnum x = GetMaxValue<MyEnum>(); //In newer versions of C# (7.3+)
MyEnum y = GetMaxValueOld<MyEnum>();
}
public static TEnum GetMaxValue<TEnum>()
where TEnum : Enum
{
return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Max();
}
//When C# version is smaller than 7.3, use this:
public static TEnum GetMaxValueOld<TEnum>()
where TEnum : IComparable, IConvertible, IFormattable
{
Type type = typeof(TEnum);
if (!type.IsSubclassOf(typeof(Enum)))
throw new
InvalidCastException
("Cannot cast '" + type.FullName + "' to System.Enum.");
return (TEnum)Enum.ToObject(type, Enum.GetValues(type).Cast<int>().Last());
}
enum MyEnum
{
ValueOne,
ValueTwo
}
VB:
Public Function GetMaxValue _
(Of TEnum As {IComparable, IConvertible, IFormattable})() As TEnum
Dim type = GetType(TEnum)
If Not type.IsSubclassOf(GetType([Enum])) Then _
Throw New InvalidCastException _
("Cannot cast '" & type.FullName & "' to System.Enum.")
Return [Enum].ToObject(type, [Enum].GetValues(type) _
.Cast(Of Integer).Last)
End Function

This is slightly nitpicky but the actual maximum value of any enum is Int32.MaxValue (assuming it's a enum derived from int). It's perfectly legal to cast any Int32 value to an any enum regardless of whether or not it actually declared a member with that value.
Legal:
enum SomeEnum
{
Fizz = 42
}
public static void SomeFunc()
{
SomeEnum e = (SomeEnum)5;
}

After tried another time, I got this extension method:
public static class EnumExtension
{
public static int Max(this Enum enumType)
{
return Enum.GetValues(enumType.GetType()).Cast<int>().Max();
}
}
class Program
{
enum enum1 { one, two, second, third };
enum enum2 { s1 = 10, s2 = 8, s3, s4 };
enum enum3 { f1 = -1, f2 = 3, f3 = -3, f4 };
static void Main(string[] args)
{
Console.WriteLine(enum1.one.Max());
}
}

Use the Last function could not get the max value. Use the "max" function could. Like:
class Program
{
enum enum1 { one, two, second, third };
enum enum2 { s1 = 10, s2 = 8, s3, s4 };
enum enum3 { f1 = -1, f2 = 3, f3 = -3, f4 };
static void Main(string[] args)
{
TestMaxEnumValue(typeof(enum1));
TestMaxEnumValue(typeof(enum2));
TestMaxEnumValue(typeof(enum3));
}
static void TestMaxEnumValue(Type enumType)
{
Enum.GetValues(enumType).Cast<Int32>().ToList().ForEach(item =>
Console.WriteLine(item.ToString()));
int maxValue = Enum.GetValues(enumType).Cast<int>().Max();
Console.WriteLine("The max value of {0} is {1}", enumType.Name, maxValue);
}
}

In agreement with Matthew J Sullivan, for C#:
Enum.GetValues(typeof(MyEnum)).GetUpperBound(0);
I'm really not sure why anyone would want to use:
Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Last();
...As word-for-word, semantically speaking, it doesn't seem to make as much sense? (always good to have different ways, but I don't see the benefit in the latter.)

There are methods for getting information about enumerated types under System.Enum.
So, in a VB.Net project in Visual Studio I can type "System.Enum." and the intellisense brings up all sorts of goodness.
One method in particular is System.Enum.GetValues(), which returns an array of the enumerated values. Once you've got the array, you should be able to do whatever is appropriate for your particular circumstances.
In my case, my enumerated values started at zero and skipped no numbers, so to get the max value for my enum I just need to know how many elements were in the array.
VB.Net code snippets:
'''''''
Enum MattType
zerothValue = 0
firstValue = 1
secondValue = 2
thirdValue = 3
End Enum
'''''''
Dim iMax As Integer
iMax = System.Enum.GetValues(GetType(MattType)).GetUpperBound(0)
MessageBox.Show(iMax.ToString, "Max MattType Enum Value")
'''''''

I used the following when I needed the min and max values of my enum.
I just set a min equal to the lowest value of the enumeration and a max equal to the highest value in the enumeration as enum values themselves.
public enum ChannelMessageTypes : byte
{
Min = 0x80, // Or could be: Min = NoteOff
NoteOff = 0x80,
NoteOn = 0x90,
PolyKeyPressure = 0xA0,
ControlChange = 0xB0,
ProgramChange = 0xC0,
ChannelAfterTouch = 0xD0,
PitchBend = 0xE0,
Max = 0xE0 // Or could be: Max = PitchBend
}
// I use it like this to check if a ... is a channel message.
if(... >= ChannelMessageTypes.Min || ... <= ChannelMessages.Max)
{
Console.WriteLine("Channel message received!");
}

In F#, with a helper function to convert the enum to a sequence:
type Foo =
| Fizz = 3
| Bang = 2
// Helper function to convert enum to a sequence. This is also useful for iterating.
// stackoverflow.com/questions/972307/can-you-loop-through-all-enum-values-c
let ToSeq (a : 'A when 'A : enum<'B>) =
Enum.GetValues(typeof<'A>).Cast<'B>()
// Get the max of Foo
let FooMax = ToSeq (Foo()) |> Seq.max
Running it...
> type Foo = | Fizz = 3 | Bang = 2
> val ToSeq : 'A -> seq<'B> when 'A : enum<'B>
> val FooMax : Foo = Fizz
The when 'A : enum<'B> is not required by the compiler for the definition, but is required for any use of ToSeq, even by a valid enum type.

It is not usable in all circumstances, but I often define the max value myself:
enum Values {
one,
two,
tree,
End,
}
for (Values i = 0; i < Values.End; i++) {
Console.WriteLine(i);
}
var random = new Random();
Console.WriteLine(random.Next((int)Values.End));
Of course this won't work when you use custom values in an enum, but often it can be an easy solution.

Related

Getting an Enum member by its index (not the value assigned to it) in c#

in JavaScript world you can get an enum value according to its index in the object (not the value assigned to the enum member, but always the nth member of that enum):
const myEnum = {
Hello: 1,
Bye: 2,
Greeting: 3
}
const value = myEnum[Object.keys(myEnum)[0]];
console.log(value) // it returns 1
I was wondering if it's possible to have this kind of behavior in C# too.
I am trying to find the nth member of an Enum in C# and the values in it are all different and there is no order to them (and that's exactly how I want them to be).
Update
enum CSharpEnum {
SomeValue = 4,
AnotherValue = 2,
AndAnotherOne = 1
}
I get some indexes (like n) from somewhere else and I want to get the nth memeber of CSharpEnum. An example:
var index = 2;
var member // a way to get the member and it should return 1 (AndAnotherOne)
// because it is the third member (0, 1, 2)
Update 2
It seems my question is not clear enough so here is a link to a dotnetfiddle playground.
In one of the answers there was a GetValues method which made a list of enum values but the enum members got rearranged in it.
I have an enum in the playground and I want to get the third (0, 1, 2) member for example which is Want. Is there a way I can get that?
With enum
public enum Test
{
hello,
world
}
Create an array with
var enums = (Test[])Enum.GetValues(typeof(Test));
And now it's indexable.
Given
public enum myEnum
{
Hello = 1,
Bye = 2,
Greeting = 3
}
the Enum Class has a static method GetValues(Type) that returns an array TEnum[] of the values of this enum:
myEnum[] enumArray = (myEnum[])Enum.GetValues(typeof(myEnum));
myEnum value = enumArray[i]; // { [0] = Hello, [1] = Bye, [3] = Greeting }
Newer versions of the Framework have a generic overload (since .NET Framework 5.0?):
myEnum[] enumArray = Enum.GetValues<myEnum>();
myEnum value = enumArray[i];
UPDATE
The purpose of an enumeration type is to provide a set of named constants having an underlying integral numeric type. These constants are not indexed and have no particular order defined. If you want to have them indexed, insert them into an array
enum myEnum {
SomeValue = 4,
AnotherValue = 2,
AndAnotherOne = 1
}
static readonly myEnum[] enumArray = new[] {
myEnum.SomeValue,
myEnum.AnotherValue,
myEnum.AndAnotherOne
};
myEnum value = enumArray[2]; // --> myEnum.AndAnotherOne
See also: Enumeration types (C# reference)

Can I store int and enum together?

Example, I have a random number, but it can have "special numbers" values. Something like that:
enum XNumber { INFINITY, NEGATIVE, int }
So I could store:
var i = XNumber.INFINITY;
var i = XNumber.NEGATIVE;
var i = (XNumber) 1;
var i = (XNumber) 500;
var i = (XNumber) -1000;
If not, what are my possibilities to do that?
An enum can be cast to/from an int provided the values match up. Note that you can assign numeric values to enum values. For instance,
namespace Test
{
enum SpecialValue
{
Zero = 0,
Five = 5,
Seventy = 70
}
private void method()
{
var five = (SpecialValue)5; // == SpecialValue.Five
int seventy = (int)SpecialValue.Seventy; // == 70
}
}
The easiest way is probably putting both the int and the enum into a struct. You can define conversion operators and arithmetic operators to make working with your type easier.
e.g.
struct XNumber {
private enum SpecialValue { Normal, Negative, Infinity}
private int value;
private SpecialValue kind;
public XNumber Infinity = new XNumber { kind = SpecialValue.Infinity };
public XNumber Negative = new XNumber { kind = SpecialValue.Negative };
public static implicit operator XNumber(int value) {
if (value < 0)
return new XNumber { kind = SpecialValue.Negative };
return new XNumber { value = value };
}
// ...
}
Something like that, depending on your exact needs.
Another way, if you don't need the full range of int, is to use special values for infinity and negative and you only need to store the int. Still a struct, you should still define conversions and operators so that everything matches up. While you can get away with just an enum, as Wai Ha Lee notes, I'd not recommend it, as you essentially have an own type that has its own semantics (just that those happen to be somewhat supported by enums in C#).

Precedence of enum names

Given the following enum:
[Flags]
public enum Intervals
{
Root = PerfectUnison,
Unison = PerfectUnison,
PerfectUnison = 1 << 0,
AugmentedUnison = MinorSecond,
MinorSecond = 1 << 1,
Second = MajorSecond,
MajorSecond = 1 << 2,
AugmentedSecond = MinorThird,
MinorThird = 1 << 3,
Third = MajorThird,
MajorThird = 1 << 4,
AugmentedThird = PerfectFourth,
DoubleAugmentedThird = Triton,
DiminishedFourth = MajorThird,
Fourth = PerfectFourth,
PerfectFourth = 1 << 5,
AugmentedFourth = Triton,
DoubleAugmentedFourth = PerfectFifth,
Triton = 1 << 6,
//...Removed for brevity, see link to code bellow
}
I'm trying this simple test:
static void Main(string[] args)
{
var values = Enum.GetValues(typeof(Intervals));
foreach (var value in values)
{
Console.WriteLine(value);
}
}
And here is the output:
PerfectUnison, PerfectUnison, PerfectUnison, AugmentedUnison, AugmentedUnison, Second, Second, MinorThird, MinorThird, DiminishedFourth, DiminishedFourth, DiminishedFourth, AugmentedThird, AugmentedThird, AugmentedThird, AugmentedThird, DoubleDiminishedSixth, DoubleDiminishedSixth etc.
While I want the enum names selected for identical values to be of the following sequence:
Root, MinorSecond, Second, MinorThird, Third, Fourth, Triton, Fifth, MinorSixth, Sixth, MinorSeventh, Seventh, Octave, MinorNinth, Ninth, Tenth, Eleventh, MajorEleventh, Thirteen
A good reproduction would also be Enum.GetNames. I want the names of the above group should always precede their value-matching names.
I'm basically looking for a documentation of the rules of precedence/priority of enum names per value.
You can play around with the code here: http://rextester.com/EJOWK87857.
Update
I'm now looking into decompiled Enum.GetNames. Looks like it uses reflection. So the question is then, "How to control the order of reflected fields?".
Without using metadata, this is not possible since the compiler may assign the constant value to each enum member. Examining the compiled IL shows that the assignment information is lost when the code is compiled:
.field public static literal valuetype .../Intervals Unison = int32(1)
.field public static literal valuetype .../Intervals PerfectUnison = int32(1)
.field public static literal valuetype .../Intervals AugmentedUnison = int32(2)
...
Since this information is lost when the source is compiled (or, at least, is not guaranteed to be available), it would not be possible to assign priority rules based on assignment at runtime. This limitation is consistent with the documentation for Enum.ToString(), which states that if multiple names are associated with the same value, the member chosen is nondeterministic:
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.
This said, a possible workaround may be to assign attribute values to the enum values that are deemed to be a priority on assignment. For instance:
[AttributeUsage(AttributeTargets.Field)]
class PriorityAttribute : Attribute { }
[Flags]
public enum Intervals
{
Root = PerfectUnison,
Unison = PerfectUnison,
[Priority]
PerfectUnison = 1 << 0,
AugmentedUnison = MinorSecond,
[Priority]
MinorSecond = 1 << 1,
Second = MajorSecond,
[Priority]
MajorSecond = 1 << 2,
AugmentedSecond = MinorThird,
...
Since the attribute information is associated with the enum values at runtime, the marked enumeration names can be accessed at runtime:
typeof(Intervals)
.GetFields()
.Where(a => a.GetCustomAttributes(typeof(PriorityAttribute), false).Length > 0)
.Select(a => a.Name))
Likewise, you can write an analogue to Enum.GetName to return only the names with the attribute defined (e.g., GetPriorityName(typeof(Intervals), 1) will always return PerfectUnison.
static string GetPriorityName(Type enumType, object v)
{
Type ut = Enum.GetUnderlyingType(enumType);
var pty = enumType.GetFields()
.Where(
a => a.IsLiteral
&& a.GetRawConstantValue().Equals(v)
&& a.GetCustomAttributes(typeof(PriorityAttribute), false).Length > 0
)
.FirstOrDefault();
if (pty == null)
return Enum.GetName(enumType, v); // default to standard if no priority defined
return pty.Name;
}

Enums - All options value

Is there a way to add an "All values" option to an enum without having to change its value every time a new value is added to the enum?
[Flags]
public enum SomeEnum
{
SomeValue = 1,
SomeValue2 = 1 << 1,
SomeValue3 = 1 << 2,
SomeValue4 = 1 << 3,
All = ?
}
Update:
Ended up inheriting from long and using long.MaxValue for All option.
Since you should define the empty value in a Flags enum such as None = 0, the simplest way of defining the Allvalue is by simply inverting all the bits inNone`.
[Flags]
enum MyEnum
{
None = 0,
A = 1,
B = 2,
C = 4,
...
All = ~None
}
Note that ~0 instead of ~None will not work for unsigned backing types as that is -1, which is not a valid value for unsigned.
Edit: Answer was modified to use an inverted None instead of an explicit constant such as 0x7FFFFFFF or ~0, as this also works for unsigned
It should be like this:
[Flags]
public enum SomeEnum
{
SomeValue = 1,
SomeValue2 = 1 << 1,
SomeValue3 = 1 << 2,
SomeValue4 = 1 << 3,
All = SomeValue | SomeValue2 | SomeValue3 | SomeValue4
}
An enum can be made of many different length integer types (short, int, long). This makes the #FFFFFFFF solution inappropriate (as pointed out in #MarcGravell comment).
An enum can be made of unsigned types (uint for isntance). This makes the -1 solution inappropriate.
My best bet is, maintenance-free:
All = ~0
The Idea is to use the behavior of the enum to calculate the last value.
Add Last field after all 'real' enum values.
Add All field equals to (Last << 1) - 3.
[Flags]
public enum SomeEnum
{
SomeValue = 1,
SomeValue2 = 1 << 1,
SomeValue3 = 1 << 2,
SomeValue4 = 1 << 3,
// Do not add values after this
Last,
All = (Last << 1) - 3,
}
I answered it at: How to use Enum with aditional options (All, None)
You can check my blog at Enum Trick for more information and ideas.
No, there is nothing built is that will make such an All option automatically update when the Enum changes.
You may want to have a special value (monitor value) that means All (say -1), even if it is not the bitwise sum of all of the options.
An alternative is to use a value that has all of the bits switched on:
All = 0xFFFFFFFF
You can use a little trick
(SomeEnum)( (1 << ( Enum.GetValues( typeof(SomeEnum) ).Length ) ) -1 )
If you added a 'None' Enum name with value = 0 ( None = 0, ) then you need to put a '-1' after the Length.
This is possible if you're okay with a static readonly field in a separate type, rather than as a const enum field:
[Flags]
public enum SomeEnum
{
None = 0,
SomeValue = 1,
SomeValue2 = 1 << 1,
SomeValue3 = 1 << 2,
SomeValue4 = 1 << 3,
}
public static class SomeEnumUtility {
private static readonly SomeEnum[] _someEnumValues = (SomeEnum[])Enum.GetValues( typeof(SomeEnum) );
public static readonly SomeEnum SomeEnum_All = GetSomeEnumAll();
// Unfortunately C# does not support "enum generics" otherwise this could be a generic method for any Enum type
private static SomeEnum GetSomeEnumAll() {
SomeEnum value = SomeEnum.None; // or `(SomeEnum)0;` if None is undefined.
foreach(SomeEnum option in _someEnumValues) {
value |= option;
}
return value;
}
}
Then you can get SomeEnumUtility.SomeEnum_All. As it's a static readonly the computation is only performed once, in a thread-safe manner.
As I wrote in the code-comment, it's unfortunate that C# does not support enum generics, otherwise you could do this:
private static TEnum GetEnumAllFlags<TEnum>() where TEnum : enum {
TEnum[] allValues = Enum.GetValues<TEnum>();
TEnum value = (TEnum)0;
foreach(TEnum option in allValues) {
value |= option;
}
return value;
}
Oh well :(
public static T EnumSetAll<T>() where T : struct, Enum
{
string str = string.Join(", ", Enum.GetNames(typeof(T)));
if (Enum.TryParse<T>(str, out var e))
return e;
return default;
}

Check that integer type belongs to enum member

I want to check that some integer type belongs to (an) enumeration member.
For Example,
public enum Enum1
{
member1 = 4,
member2 = 5,
member3 = 9,
member4 = 0
}
Enum1 e1 = (Enum1)4 gives me member1
Enum1 e2 = (Enum1)10 gives me nothing and I want to check it.
Use Enum.IsDefined
Enum.IsDefined(typeof(Enum1), 4) == true
but
Enum.IsDefined(typeof(Enum1), 1) == false
As Sam says, you can use IsDefined. This is somewhat awkward though. You may want to look at my Unconstrained Melody library which would let you us:
Enum1 e2 = (Enum1)10;
if (e2.IsNamedValue()) // Will return false
{
}
It's probably not worth it for a single enum call, but if you're doing a lot of stuff with enums you may find some useful things in there.
It should be quicker than Enum.IsDefined btw. It only does a linear scan at the moment, but let me know if you need that to be improved :) (Most enums are small enough that they probably wouldn't benefit from a HashSet, but we could do a binary search...)
int testNum = 5;
bool isMember = Enum.GetValues(typeof(Enum1)).Cast<int>().Any(x => x == testNum);
You look through the values of the enum and compare them to the integer.
static bool EnumTest(int testVal, Enum e)
{
bool result = false;
foreach (var val in Enum.GetValues(typeof(Enum1)))
{
if ((int)val == testVal)
{
result = true;
break;
}
}
return result;
}
Edit: Looks like Sam has a better solution.
You can use Enum.GetValues to get all defined values. Then check if your value exists in that list.
http://msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx
Be careful this won't work if you have an enum for 3 (Apples and Pears) the methods above won't detect it as valid.
[Flags]
public enum Fruit
{
Apples=1,
Pears=2,
Oranges =4,
}
Here's a succinct little snippet from an extension method I wrote a few years ago. Combines TryParse with IsDefined to do it all in one swoop and handle values that don't exist in the enum.
if (value != null)
{
TEnum result;
if (Enum.TryParse(value.ToString(), true, out result))
{
// since an out-of-range int can be cast to TEnum, double-check that result is valid
if (Enum.IsDefined(typeof(TEnum), result.ToString() ?? string.Empty))
{
return result;
}
}
}
Here's the extension for integer values
public static TEnum ParseToEnum<TEnum>(this int value, TEnum? defaultValue = null, bool useEnumDefault = false) where TEnum : struct
{
return ParseToEnumInternal(value, defaultValue, useEnumDefault);
}
And a usage
public enum Test
{
Value1 = 1,
Value2 = 3
}
var intValue = 1;
var enumParsed = intValue.ParseToEnum<Test>(); // converts to Test.Value1
intValue = 2;
enumParsed = intValue.ParseToEnum<Test>(); // either throws or converts to supplied default
enumParsed = 3.ParseToEnum<Test>(); // converts to Test.Value2
Some people don't like how it dangles off the end of the (potentially nullable) value, but I have an extension that handles null values of nullable types (int?) and I like it myself, so ...
I can post like a Gist of the whole extension method with all the overloads if you're interested.
Use:
if (Enum.IsDefined(typeof(Fruit),e2))
{
//Valid Value
}
else
{
//Invalid ENum Value
}
Found this useful. https://stackoverflow.com/a/64374930/16803533
no need to use IsDefined and No range checking

Categories