Getting item names from enums with multiple zero values - c#

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

Related

How to get enum by index with different set values? [duplicate]

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

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

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

Is there a better way to check for valid values?

I have a property in my class that can only be one of several values, what is the best way to limit the input on this property.
Here is what I'm doing now, and I'm sure there must be a better way.
public void SetValue(int value)
{
if(value != 1 ||
value != 4 ||
value != 8 ||
value != 16 ||
value != 32 ||
value != 64, ||
value != 128)
{
property_value = 1;
}
else
{
property_value = value;
}
}
Instead of in int, use an Enum with these values.
I am sure each value has a specific meaning - expose these as enum members.
This may not eliminate all issues (since an Enum is simply a wrapper over an integer type and can still get assigned a value that doesn't exist in the enumeration), but should take care of most problems, so long as you are consistent about only passing values from the enumeration itself.
In any rate, you can then simply test the passed in value against the enumeration and throw an exception if it isn't a valid member.
Use enum instead of this numeric values like:
enum Numbers { Name1 = 1, Name2 = 4 ... }
and then you can easilly check if value is one of enum element:
Enum.IsDefined(typeof(Numbers), value );
For your example, you can just do:
property_value = 1;
since your if condition will always be true.
If you want to restrict it to a number of possibilities you could:
Declare an enum:
public enum Value
{
Default = 1,
Option1 = 4,
...
}
or have a collection of valid values to check:
int[] validValues = new int[] { 1, 4, 8, 16, 32, 64, 128 };
property_value = validValues.Contains(value) ? value : 1;
Although I would prefer to throw an exception on invalid input.
I think you should consider using an enum:
public enum MyEnum
{
These,
Are,
Valid,
Values
}
public void SetValue(MyEnum _value)
{
// Only MyEnum values allowed here!
}
if(((value & (value − 1)) == 0) && value != 2 && value <= 128)
property_value = 1;
else
property_value = value;
(value & (value − 1)) is a fast way to check if value is a power of two.
As an example: value = 4:
(4(10) & (3(10)) =
100(2) & 011(2) =
000(2) = 0
value = 5
(5(10) & (4(10)) =
101(2) & 100(2) =
100(2) =
4
You could use an enum and check using Enum.IsDefined(value). But then you'd have to think of a (meaningfull) name for all the possible values.
I think we're missing the INTENT of the function here.
It looks like a bit mask check to me. If that's the case, he's missing 2 from the code sample. Also, note that he's not discarding a value if it isn't one of those specific bits: he preserves it. If it is a value equal to a specific bit (and only that bit) he coerces it to 1.
I think the sample provided by Lee works best in this case; it's simple and to the point. Also, if the check is widened to account for 16 bits (or even 32), it will easily catch them all.

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.

Categories