19

I was working on a web service method that will receive an array of ints as parameter, and then, inside the method, I converted the values in the array into enum values, and stored them in a enum list. However, when a value that's not in the enum is passed, it is added to the enum list with no problems. No InvalidCastException, nothing. I made a test project that looks like this:

static class Program
{
    static void Main(string[] args)
    {
        List<TestValues> values = new List<TestValues>() {
            TestValues.Value1,
            TestValues.Value2,
            (TestValues)15
        };

        foreach (var val in values)
            Console.WriteLine(val);

        Console.Read();
    }

    enum TestValues
    { 
        Value1 = 2,
        Value2 = 4,
        Value3 = 8
    }
}

When I run it, the output is:

Value1
Value2
15

For my web service, I'll implement a validation, so this will never hapen at all. But... this is weird! Shouldn't the runtime throw a InvalidCastException or ArgumentOutOfRangeException, or something similar? Since I got a list of enums (and not int values), I want the values to be limitted to the values of the enum (that's what an enum is for).

Am I missing something? Is this a .NET bug, a C# bug or is there something I don't know with enums?

Yuck
  • 49,664
  • 13
  • 105
  • 135
Raphael
  • 1,847
  • 1
  • 17
  • 29
  • 1
    Read this one: [Why does casting int to invalid enum value NOT throw exception?][1] [1]: http://stackoverflow.com/questions/6413804/why-does-casting-int-to-invalid-enum-value-not-throw-exception – vinayvasyani Aug 25 '11 at 18:08

5 Answers5

22

You can assign any value to an enum that the underlying type allows. By default, the underlying type is int, so you can assign any int value to the enum.

The main reason for this is because if you have a [Flags] enumeration, you want to be able to assign composite values:

[Flags]
public enum MyFlags
{
    A = 1,
    B = 2
}

MyFlags flags = (MyFlags)3; // Equivalent to setting A and B

Preferably you'd just use the enumeration values to do that, though:

MyFlags flags = MyFlags.A | MyFlags.B; // Sets flags to 3

It's important to note, of course, that the [Flags] attribute isn't required to enable this assignment. All enums have this property, by design.

As pointed out by a number of people, you can use Enum.IsDefined() to determine if a particular value is valid for a given enum. That should help with your validation.

dlev
  • 48,024
  • 5
  • 125
  • 132
  • I completly forgot about `[Flags]`, for I rarely use it. To me, it seems like a clear advantage for that use, but a little odd for the more common use of enums. By the way, the comments and the other answers provide nice complementary links to the subject. – Raphael Aug 25 '11 at 18:21
6

Yes, there is no check for defined values when you convert to an enum value.

You can use the IsDefined method to check if a specific value is defined:

if (Enum.IsDefined(typeof(TestValues), value)) ...
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
1

You can always cast any int value to an enum based on int. This is by design, as the cast would be a lot slower if it had to check all legal values.

Jonas Høgh
  • 10,358
  • 1
  • 26
  • 46
1

To determine if the specified int is defined within the enum you can use Enum.IsDefined.

Enum.IsDefined(typeof(TestValues), 15);
JK.
  • 5,126
  • 1
  • 27
  • 26
1

You should read the following thread:

Why does Enum.Parse create undefined entries?

In short, this is valid. If you want to check if the value is defined, use Enum.IsDefined.

Community
  • 1
  • 1
JohnD
  • 14,327
  • 4
  • 40
  • 53