There is something that I cannot understand in C#. You can cast an out-of-range int into an enum and the compiler does not flinch. Imagine this
Old question, but this confused me recently, and Google brought me here. I found an article with further searching that finally made it click for me, and thought I'd come back and share.
The gist is that Enum is a struct, which means it's a value type (source). But in essence it acts as a derived type of the underlying type (int, byte, long, etc.). So if you can think of an Enum type as really just the same thing as its underlying type with some added functionality/syntactic sugar (as Otávio said) then you'll be aware of this "problem" and be able to protect against it.
Speaking of that, here is the heart of an extension method I wrote to easily convert/parse things to an 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()))
{
return result;
}
}
}
// deal with null and defaults...
The variable value there is of type object, as this extension has "overloads" that accept int, int?, string, Enum, and Enum?. They're all boxed and sent to the private method that does the parsing. By using both TryParse and IsDefined in that order, I can parse all the types just mentioned, including mixed case strings, and it's pretty robust.
Usage is like so (assumes NUnit):
[Test]
public void MultipleInputTypeSample()
{
int source;
SampleEnum result;
// valid int value
source = 0;
result = source.ParseToEnum();
Assert.That(result, Is.EqualTo(SampleEnum.Value1));
// out of range int value
source = 15;
Assert.Throws(() => source.ParseToEnum());
// out of range int with default provided
source = 30;
result = source.ParseToEnum(SampleEnum.Value2);
Assert.That(result, Is.EqualTo(SampleEnum.Value2));
}
private enum SampleEnum
{
Value1,
Value2
}
Hope that helps somebody.
Disclaimer: we do not use flags/bitmask enums... this has not been tested with that usage scenario and probably wouldn't work.