Precedence of enum names - c#

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;
}

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)

Check if an enum contains more than one flag [duplicate]

This question already has answers here:
How do I check if more than one enum flag is set?
(5 answers)
Test that only a single bit is set in Flags Enum [duplicate]
(1 answer)
Closed 2 years ago.
I am trying to check if an "enum instance" contains more than one flag.
[Flags]
public enum Foo
{
Bar = 1,
Far = 2
}
var multiState = Foo.Bar | Foo.Far;
MoreThanOneFlag(multiState); // True
var singleState = Foo.Bar;
MoreThanOneFlag(singleState); // False
Additionally I really don't wanna use something like the following:
var state = Foo.Bar | Foo.Far;
Console.WriteLine(state.ToString().Count(x => x == ',') > 0); // True
Note, I do not care which Flags the "instance" contains, I just want to know if there are more than one.
I am trying to check if an "enum instance" contains more than one flag.
I do not care which Flags the "instance" contains, I just want to know if there are more than one
Additionally I really don't wanna use something like the following:
var state = Foo.Bar | Foo.Far;
Console.WriteLine(state.ToString().Count(x => x == ',') > 0); // True
There are more than a few different ways to accomplish what you want, I propose to do a bit (bitwise) check:
public static bool MoreThanOneFlag<TValue>(TValue flag) where TValue : Enum => (Convert.ToInt32(flag) & (Convert.ToInt32(flag) - 1)) != 0;
In the above code block, we check if flag is not a power of two by checking using flag & (flag-1)) != 0 (the & operator) which computes the bitwise logical AND of its operands. If there's only one flag set, we assume then that the value would be a power of two, otherwise it's a non power of two.
Or, if you don't want a helper function just perform that check anywhere:
bool value = (multiState & (multiState -1)) != 0;
For more information about bitwise, please check out more here.
References :
Bitwise and shift operators (C# reference)
You can use the binary logarithm function on the enum value and then check if the result is an integer.
The following example defines am Extension Method helper, which returns true when multiple flags are set:
HelperExtenxsions.cs
public static class HelperExtenxsions
{
public static bool HasMultipleFlags(this IConvertible enumValue)
{
return Math.Log(enumValue.ToInt32(CultureInfo.InvariantCulture.NumberFormat), 2) % 1 != 0;
}
}
Foo.cs
[Flags]
public enum Foo
{
Bar = 1,
Far = 2
}
Program.cs
public static void Main()
{
var enumValue = Foo.Bar | Foo.Far;
Console.WriteLine(enumValue.HasMultipleFlags()); // Prints 'True'
enumValue = Foo.Bar;
Console.WriteLine(enumValue.HasMultipleFlags()); // Prints 'False'
}
You can use Enum.GetValues in conjunction with Enum.HasFlag(Enum) to iterate over each constant & determine if the bit field(s) are set in the current Instance and return its count.
[Flags]
public enum Foo
{
One = 1,
Two = 2,
Four = 4,
Eight = 8
}
var state1 = Foo.One;
var state2 = Foo.Two;//
var state3 = Foo.One | Foo.Two;
var state4 = Foo.Two | Foo.Four;
Console.WriteLine(MoreThanOneFlag(state1));//false
Console.WriteLine(MoreThanOneFlag(state2));//false
Console.WriteLine(MoreThanOneFlag(state3));//true
Console.WriteLine(MoreThanOneFlag(state4));// true
private static bool MoreThanOneFlag<TEnum>(TEnum state) where TEnum : Enum
{
var names = Enum.GetValues(typeof(TEnum));
var Flagcounter = names.OfType<TEnum>().Where(x=>state.HasFlag((TEnum)x)).Count();
return Flagcounter > 1 ? true : false;
}
Note: While Enum.HasFlags may not the apt solution if you're app demands performance but it is much reliable, clean, and makes the code very obvious and expressive
Reference:
C# Enum.HasFlag vs. Bitwise AND Operator Check

Getting item names from enums with multiple zero values

I'm having difficulties working with some legacy enums that have multiple zero values. Whenever I call ToString on one of the non-zero values, all but the first zero value is included.
Is there any way to isolate the non-zero value name without resorting to string manipulation or reflection?
//all of the following output "Nada, Zilch, One"
Console.WriteLine(TestEnum.One);
Console.WriteLine(Convert.ToString(TestEnum.One));
Console.WriteLine(TypeDescriptor.GetConverter(typeof(TestEnum))
.ConvertToString(TestEnum.One));
[Flags]
enum TestEnum
{
Zero = 0,
Nada = 0,
Zilch = 0,
One = 1
}
Edit
I understand that having multiple items with the same value is not recommended however the enum in question is defined in a legacy assembly that I can't change. In fact, there are 12 public enums in mscorlib v4 that break this recommendation, as determined by the following simple LINQ query:
var types = typeof (void).Assembly.GetTypes()
.Where(type => type.IsEnum &&
type.IsPublic &&
Enum.GetValues(type).Cast<object>()
.GroupBy(value => value)
.Any(grp => grp.Count() > 1))
.ToList();
Here is one option. It works, but it's a bit ugly. The values / names variables won't change, so they only need to be calculated once.
Assuming you have a slightly more complicated enum, such as:
[Flags]
public enum TestEnum
{
Zero = 0,
Nada = 0,
Zilch = 0,
One = 1,
Two = 2,
Three = 3,
Four = 4
}
Here is some code you could use:
var input = TestEnum.One | TestEnum.Two;
var values = (TestEnum[]) Enum.GetValues(typeof (TestEnum));
var names = Enum.GetNames(typeof (TestEnum));
var result = values
.Select((value, index) =>
input == value || (value != 0 && (input & value) == value)
? names[index]
: null)
.Where(name => name != null);
var text = string.Join(", ", result);
Console.WriteLine(text);
Alright, first Microsoft recommends against this strongly. Some of the stronger words I've heard them use for something they don't enforce on compile:
Avoid setting a flags enumeration value to zero, unless the value is used to indicate that all flags are cleared. Such a value should be named appropriately as described in the next guideline... Do name the zero value of flags enumerations None. For a flags enumeration, the value must always mean all flags are cleared.
Ok, so why is this happening? From this question I take it's Enum.ToString behaving strangely:
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.
EDIT: I'm able to reproduce your results, but I can't find any more documentation on why it would start printing out the other 0 values. I would expect it to print NONE of them.
Can you just right-click->refactor->rename them all the same and then delete the others? It seems easier and less against what Microsoft recommends.
Assuming you have a slightly more complex enum, such as:
[Flags]
public enum TestEnum
{
Zero = 0,
Nada = 0,
Zilch = 0,
One = 1,
Two = 2,
Four = 4,
}
You could implement a simple method that returns the string value for you, like this:
public static string TestEnumToString(TestEnum value)
{
var result = new List();
if (value == TestEnum.Zero)
{
result.Add("Zero");
}
if (value == TestEnum.Nada)
{
result.Add("Nada");
}
if (value == TestEnum.Zilch)
{
result.Add("Zilch");
}
if ((value & TestEnum.One) != 0)
{
result.Add("One");
}
if ((value & TestEnum.Two) != 0)
{
result.Add("Two");
}
if ((value & TestEnum.Four) != 0)
{
result.Add("Four");
}
return string.Join(",", result);
}

Is there a way to check if int is legal enum in C#?

I've read a few SO posts and it seems most basic operation is missing.
public enum LoggingLevel
{
Off = 0,
Error = 1,
Warning = 2,
Info = 3,
Debug = 4,
Trace = 5
};
if (s == "LogLevel")
{
_log.LogLevel = (LoggingLevel)Convert.ToInt32("78");
_log.LogLevel = (LoggingLevel)Enum.Parse(typeof(LoggingLevel), "78");
_log.WriteDebug(_log.LogLevel.ToString());
}
This causes no exceptions, it's happy to store 78. Is there a way to validate a value going into an enum?
Check out Enum.IsDefined
Usage:
if(Enum.IsDefined(typeof(MyEnum), value))
MyEnum a = (MyEnum)value;
This is the example from that page:
using System;
[Flags] public enum PetType
{
None = 0, Dog = 1, Cat = 2, Rodent = 4, Bird = 8, Reptile = 16, Other = 32
};
public class Example
{
public static void Main()
{
object value;
// Call IsDefined with underlying integral value of member.
value = 1;
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
// Call IsDefined with invalid underlying integral value.
value = 64;
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
// Call IsDefined with string containing member name.
value = "Rodent";
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
// Call IsDefined with a variable of type PetType.
value = PetType.Dog;
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
value = PetType.Dog | PetType.Cat;
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
// Call IsDefined with uppercase member name.
value = "None";
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
value = "NONE";
Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
// Call IsDefined with combined value
value = PetType.Dog | PetType.Bird;
Console.WriteLine("{0:D}: {1}", value, Enum.IsDefined(typeof(PetType), value));
value = value.ToString();
Console.WriteLine("{0:D}: {1}", value, Enum.IsDefined(typeof(PetType), value));
}
}
The example displays the following output:
// 1: True
// 64: False
// Rodent: True
// Dog: True
// Dog, Cat: False
// None: True
// NONE: False
// 9: False
// Dog, Bird: False
The above solutions do not deal with [Flags] situations.
My solution below may have some performance issues (I'm sure one could optimise in various ways) but essentially it will always prove whether an enum value is valid or not.
It relies on three assumptions:
Enum values in C# are only allowed to be int, absolutely nothing else
Enum names in C# must begin with an alphabetic character
No valid enum name can being with a minus sign: -
Calling ToString() on an enum returns either the int value if no enum (flag or not) is matched. If an allowed enum value is matched, it will print the name of the match(es).
So:
[Flags]
enum WithFlags
{
First = 1,
Second = 2,
Third = 4,
Fourth = 8
}
((WithFlags)2).ToString() ==> "Second"
((WithFlags)(2 + 4)).ToString() ==> "Second, Third"
((WithFlags)20).ToString() ==> "20"
With these two rules in mind we can assume that if the .NET Framework does its job correctly that any calls to a valid enum's ToString() method will result in something that has an alphabetic character as its first character:
public static bool IsValid<TEnum>(this TEnum enumValue)
where TEnum : struct
{
var firstChar = enumValue.ToString()[0];
return (firstChar < '0' || firstChar > '9') && firstChar != '-';
}
One could call it a "hack", but the advantages are that by relying on Microsoft's own implementation of Enum and C# standards, you're not relying on your own potentially buggy code or checks. In situations where performance is not exceptionally critical, this will save a lot of nasty switch statements or other checks!
Edit
Thanks to #ChaseMedallion for pointing out that my original implementation did not support negative values. This has been remedied and tests provided.
And the tests to back it up:
[TestClass]
public class EnumExtensionsTests
{
[Flags]
enum WithFlags
{
First = 1,
Second = 2,
Third = 4,
Fourth = 8
}
enum WithoutFlags
{
First = 1,
Second = 22,
Third = 55,
Fourth = 13,
Fifth = 127
}
enum WithoutNumbers
{
First, // 1
Second, // 2
Third, // 3
Fourth // 4
}
enum WithoutFirstNumberAssigned
{
First = 7,
Second, // 8
Third, // 9
Fourth // 10
}
enum WithNagativeNumbers
{
First = -7,
Second = -8,
Third = -9,
Fourth = -10
}
[TestMethod]
public void IsValidEnumTests()
{
Assert.IsTrue(((WithFlags)(1 | 4)).IsValid());
Assert.IsTrue(((WithFlags)(1 | 4)).IsValid());
Assert.IsTrue(((WithFlags)(1 | 4 | 2)).IsValid());
Assert.IsTrue(((WithFlags)(2)).IsValid());
Assert.IsTrue(((WithFlags)(3)).IsValid());
Assert.IsTrue(((WithFlags)(1 + 2 + 4 + 8)).IsValid());
Assert.IsFalse(((WithFlags)(16)).IsValid());
Assert.IsFalse(((WithFlags)(17)).IsValid());
Assert.IsFalse(((WithFlags)(18)).IsValid());
Assert.IsFalse(((WithFlags)(0)).IsValid());
Assert.IsTrue(((WithoutFlags)1).IsValid());
Assert.IsTrue(((WithoutFlags)22).IsValid());
Assert.IsTrue(((WithoutFlags)(53 | 6)).IsValid()); // Will end up being Third
Assert.IsTrue(((WithoutFlags)(22 | 25 | 99)).IsValid()); // Will end up being Fifth
Assert.IsTrue(((WithoutFlags)55).IsValid());
Assert.IsTrue(((WithoutFlags)127).IsValid());
Assert.IsFalse(((WithoutFlags)48).IsValid());
Assert.IsFalse(((WithoutFlags)50).IsValid());
Assert.IsFalse(((WithoutFlags)(1 | 22)).IsValid());
Assert.IsFalse(((WithoutFlags)(9 | 27 | 4)).IsValid());
Assert.IsTrue(((WithoutNumbers)0).IsValid());
Assert.IsTrue(((WithoutNumbers)1).IsValid());
Assert.IsTrue(((WithoutNumbers)2).IsValid());
Assert.IsTrue(((WithoutNumbers)3).IsValid());
Assert.IsTrue(((WithoutNumbers)(1 | 2)).IsValid()); // Will end up being Third
Assert.IsTrue(((WithoutNumbers)(1 + 2)).IsValid()); // Will end up being Third
Assert.IsFalse(((WithoutNumbers)4).IsValid());
Assert.IsFalse(((WithoutNumbers)5).IsValid());
Assert.IsFalse(((WithoutNumbers)25).IsValid());
Assert.IsFalse(((WithoutNumbers)(1 + 2 + 3)).IsValid());
Assert.IsTrue(((WithoutFirstNumberAssigned)7).IsValid());
Assert.IsTrue(((WithoutFirstNumberAssigned)8).IsValid());
Assert.IsTrue(((WithoutFirstNumberAssigned)9).IsValid());
Assert.IsTrue(((WithoutFirstNumberAssigned)10).IsValid());
Assert.IsFalse(((WithoutFirstNumberAssigned)11).IsValid());
Assert.IsFalse(((WithoutFirstNumberAssigned)6).IsValid());
Assert.IsFalse(((WithoutFirstNumberAssigned)(7 | 9)).IsValid());
Assert.IsFalse(((WithoutFirstNumberAssigned)(8 + 10)).IsValid());
Assert.IsTrue(((WithNagativeNumbers)(-7)).IsValid());
Assert.IsTrue(((WithNagativeNumbers)(-8)).IsValid());
Assert.IsTrue(((WithNagativeNumbers)(-9)).IsValid());
Assert.IsTrue(((WithNagativeNumbers)(-10)).IsValid());
Assert.IsFalse(((WithNagativeNumbers)(-11)).IsValid());
Assert.IsFalse(((WithNagativeNumbers)(7)).IsValid());
Assert.IsFalse(((WithNagativeNumbers)(8)).IsValid());
}
}
The canonical answer would be Enum.IsDefined, but that is a: a bit slow if used in a tight loop, and b: not useful for [Flags] enums.
Personally, I'd stop worrying about that, and just switch appropriately, remembering:
if it is OK not to recognise everything (and just not do anything), then don't add a default: (or have an empty default: explaining why)
if there is a sensible default behaviour, put that in the default:
otherwise, handle the ones you know about and throw an exception for the rest:
Like so:
switch(someflag) {
case TriBool.Yes:
DoSomething();
break;
case TriBool.No:
DoSomethingElse();
break;
case TriBool.FileNotFound:
DoSomethingOther();
break;
default:
throw new ArgumentOutOfRangeException("someflag");
}
Use:
Enum.IsDefined ( typeof ( Enum ), EnumValue );
Use Enum.IsDefined.
In order to deal with [Flags] you can also use this solution from C# Cookbook:
First, add a new ALL value to your enum:
[Flags]
enum Language
{
CSharp = 1, VBNET = 2, VB6 = 4,
All = (CSharp | VBNET | VB6)
}
Then, check if the value is in ALL:
public bool HandleFlagsEnum(Language language)
{
if ((language & Language.All) == language)
{
return (true);
}
else
{
return (false);
}
}
As the others said, Enum.IsDefined returns false even if you have a valid combination of bit flags for an enum decorated with the FlagsAttribute.
Sadly, the only way to create a method returning true for valid bit flags is a bit lengthy:
public static bool ValidateEnumValue<T>(T value) where T : Enum
{
// Check if a simple value is defined in the enum.
Type enumType = typeof(T);
bool valid = Enum.IsDefined(enumType, value);
// For enums decorated with the FlagsAttribute, allow sets of flags.
if (!valid && enumType.GetCustomAttributes(typeof(FlagsAttribute), false)?.Any() == true)
{
long mask = 0;
foreach (object definedValue in Enum.GetValues(enumType))
mask |= Convert.ToInt64(definedValue);
long longValue = Convert.ToInt64(value);
valid = (mask & longValue) == longValue;
}
return valid;
}
You may want to cache the results of GetCustomAttribute in a dictionary:
private static readonly Dictionary<Type, bool> _flagEnums = new Dictionary<Type, bool>();
public static bool ValidateEnumValue<T>(T value) where T : Enum
{
// Check if a simple value is defined in the enum.
Type enumType = typeof(T);
bool valid = Enum.IsDefined(enumType, value);
if (!valid)
{
// For enums decorated with the FlagsAttribute, allow sets of flags.
if (!_flagEnums.TryGetValue(enumType, out bool isFlag))
{
isFlag = enumType.GetCustomAttributes(typeof(FlagsAttribute), false)?.Any() == true;
_flagEnums.Add(enumType, isFlag);
}
if (isFlag)
{
long mask = 0;
foreach (object definedValue in Enum.GetValues(enumType))
mask |= Convert.ToInt64(definedValue);
long longValue = Convert.ToInt64(value);
valid = (mask & longValue) == longValue;
}
}
return valid;
}
Note that the code above uses the new Enum constraint on T which is only available since C# 7.3. You need to pass an object value in older versions and call GetType() on it.
One way to do would be to rely on casting and enum to string conversion. When casting int to an Enum type the int is either converted to a corresponding enum value or the resulting enum just contains int as a value if enum value is not defined for the int.
enum NetworkStatus{
Unknown=0,
Active,
Slow
}
int statusCode=2;
NetworkStatus netStatus = (NetworkStatus) statusCode;
bool isDefined = netStatus.ToString() != statusCode.ToString();
Not tested for any edge cases.
I know this is an old question, but I ran into this today, and I wanted to expand on Josh Comley's answer (https://stackoverflow.com/a/23177585/3403999)
There's a couple of wrong assumptions in Josh's answer that I wanted to address:
It assumes that the '-' is always the negative sign. I don't know if there is any cultures that use a different sign, but .Net certainly allows for it in the NumberFormatInfo (https://learn.microsoft.com/en-us/dotnet/api/system.globalization.numberformatinfo.negativesign?view=net-5.0). About the only one I can think of that might be common is the parenthesis, ie (1) == -1.
Enum members have to start with an alphabetic character. Specifically, I know you can use an underscore as the first char. IE, enum MyEnum { _One = 1 } is valid.
Not really sure this exactly wrong, but it made the assumption that anything outside the range of '0' to '9' and '-' is a valid alphabetic character. It seemed like a bad assumption cause there are control characters outside that range that would return true - albeit, I don't think you can get those control characters into an enum member name without it throwing a compile error.
Anyway, here's my updated solution:
public static bool IsValid<TEnum>(this TEnum value) where TEnum : System.Enum
{
char first = value.ToString()[0];
return (char.IsLetter(first) || first == '_');
}
I did discover that you can use Unicode letters from other languages in enum member names (https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/identifier-names). My solution still passes in this regard. I tested with the following enum: enum MyEnum { \u05D0 }. The enum compiled, and the IsValid returned true.
I was curious what kind of performance hit you'd take going this route vs using a static helper class with a HashSet that is filled with Enum.GetValues(typeof(TEnum)) where you check to see if the HashSet contains the enum value. The thought being that both Enum.GetValues and Enum.IsDefined are just wrappers around expensive Reflection hits, so you do the Reflection once with GetValues, cache the results, and then just check the HashSet going forward.
I ran a fairly simple test with a StopWatch and Random that would generate valid & invalid enum values, and then I ran them through 3 different methods: the ToString method, the GetValues HashSet method, and the IsDefined method. I had them do each method int.MaxValue times. The results:
ToString averaged about 2 minutes every time I ran it 2 billion times.
GetValues HashSet about 50 seconds every time I ran it 2 billion times.
IsDefined about 5 minutes every time I ran it 2 billion times.
So all the solutions recommending IsDefined are probably a bad idea if performance is a concern, or your doing a loop. If you are only using it somehow validate user input on single instances, it probably doesn't matter.
For the HashSet, it's a small performance hit for each different enum you run through it (cause the first time a new enum type gets ran through generates a new static HashSet). Not scientific, but it seemed my break even point on my PC was about 200k to 300k runs for a single enum before it started out performing using the ToString method.
The ToString method, while not the fastest had the added benefit of handling Flags enums that neither the IsDefined nor HashSet accommodate.
If performance really is a concern, don't use any of these 3 methods. Instead write a method that validates on a specific enum optimized to that enum.
Also note that my tests were with relatively small enums (5 or so elements). I don't know how performance between ToString vs HashSet once you start getting into larger enums.

Getting the max value of an enum

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.

Categories