-2

I have the code below in which there are 2 enums and a function that takes base class Enum as parameter, casts the general Enum to SomeEnum and displays it. I would have expected that when you pass SomeOtherEnum in the function, a InvalidCastException to be thrown because I was suspecting that the compiler generates for every enum another type. From the behavior however, it seems that the compiler has a single generated class type and every instance has different parameters(the enums). Is this correct? If not, why is it possible to pass seemingly incompatible types and the compiler doesn't complain?

'

enum SomeEnum
{
    X1,
    X2, 
    X3
}

enum SomeOtherEnum
{
    X1,
    X2,
    X3,
    X4,
    X5
}

public static void SomeFunction(Enum someEnum)
{
    SomeEnum x = SomeEnum.X3; // some dummy init
    try
    {
        x = (SomeEnum) someEnum;
    }
    catch (InvalidCastException) 
    {
        Console.WriteLine("Exception"); // why no exception caught ? why legit cast ?
    }
    Console.WriteLine(x);
}
    private static void Main(string[] args)
    {
        SomeFunction(SomeOtherEnum.X5); // pass a different type than the one in the function
        Console.ReadKey();
    }

`

  • because in your example, your enums are ints! your method just assigns 4 to the value of `x` within `SomeFunction` – Ric Oct 07 '15 at 12:24
  • Enums have a base numerical type (the default is `int`). With that said why are you defining your method to take `Enum` instead of the more specific `SomeEnum`? – juharr Oct 07 '15 at 12:24
  • You're sidestepping the compiler's type safety by having `SomeFunction` take an `Enum` (or something that inherits from it like either `SomeEnum` or `SomeOtherEnum`) – Rowland Shaw Oct 07 '15 at 12:25
  • you can cast any int value to enum and vice versa – M.kazem Akhgary Oct 07 '15 at 12:25
  • Enum is a simple `int` under the hood. What is more, you can cast any `int` to `enum` and vice versa. So when you do a cast like `(SomeEnum)otherEnum`, the first enum type is treated like an `int`, so cast is allowed: `(SomeEnum)((int)otherEnum)`. – pwas Oct 07 '15 at 12:26
  • 1
    FYI if you just want to determine if the value is valid for a specific enum use [`Enum.IsDefined`](https://msdn.microsoft.com/en-us/library/system.enum.isdefined(v=vs.110).aspx) – juharr Oct 07 '15 at 12:27
  • Possible duplicate of [Why don't I get InvalidCastException when casting enum to integer fails?](http://stackoverflow.com/questions/5026876/why-dont-i-get-invalidcastexception-when-casting-enum-to-integer-fails) – thumbmunkeys Oct 07 '15 at 12:30
  • To all, I don't think enums are ints. I know that you can cast a number to a enum but that's just syntactic sugar(in my opinion) for initializing a class with a number. So, even if they act identical, Enum is still a different type from int. – user2436426 Oct 07 '15 at 12:55

4 Answers4

2

Your SomeFunction signature is currently instructed to accept any "Enum" datatype, of which both SomeEnum and SomeOtherEnum are.

Change your signature from:

public static void SomeFunction(Enum someEnum)

to

public static void SomeFunction(SomeEnum someEnum)

and your call to SomeFunction(SomeOtherEnum.X5) will become an error.

Jerren Saunders
  • 1,188
  • 1
  • 8
  • 26
2

Enums are basically named integers, with some compiler time checks. Still, there are a lot of way to fool the compiler into accepting invalid values for enums, e.g.

public enum First {
   One = 1, 
   Two = 2
}

First first = (First) 3;

is completely valid code.

So the line x = (SomeEnum) someEnum works, because it essentially executes as:

 x = (SomeEnum) (Enum) SomeOtherEnum.X5;

Each of the two casts are valid by themselves, even if they produce a value that makes to sense.


IMHO, enums are the one place where the C# design team completely dropped the ball - they are sufficiently different from integers, that you have to handle them differently, yet not different enough to make sense on their own.

SWeko
  • 30,434
  • 10
  • 71
  • 106
  • Well, that's not quite clear, I thought also about integers but Enum is a class. How you say, something does not make sense, the signature of the function parameter is a class but you pass a integer. How works that? – user2436426 Oct 07 '15 at 12:39
  • 1
    No, `System.Enum` is quite special, and the way defined `enum`s inherit from it is baked into the language. Any `enum` can be cast to `Enum`, and an Enum can be cast to any `enum` type - similar as the integer example I gave - and that's why your code does not throw an exception. Indeed it functions, only not in the way you intended.. – SWeko Oct 07 '15 at 13:32
1

Behind the scenes, Enums are essentially just named integers.

Because of this, when you have an Enum object (IE the base type of all enums) you can freely cast to any inherited type.

See this question for more information about why it's not an invalid cast.

Community
  • 1
  • 1
Vlad274
  • 6,514
  • 2
  • 32
  • 44
  • How can they be integers? I don't think so, Enum is a class. Sure , they behave like passing integers but you cannot pass a integer where a Enum is expected. To me , there seems to be more behind... – user2436426 Oct 07 '15 at 12:44
  • You're correct, they are not integers. However, as mentioned in other answers, the backing data is an integer. Hence, you can cast and enum to/from int. – Vlad274 Oct 07 '15 at 12:47
  • The fact that you can cast integers is probably syntactic sugar. I don't understand why the cast between enums works because apparently SomeEnum is SomeOtherEnum are different types(or not?). I worked until know in C++ and coming to C# I saw that it is much more type safe (stronger typed) and this cast left me wondering ... it kind off jumps over type safety and let you do stupid things passing enums that shouldn't be there. – user2436426 Oct 07 '15 at 13:03
  • You're not casting from SomeEnum to SomeOtherEnum. Your function accepts type Enum, so SomeOtherEnum is cast to Enum which is then cast to SomeEnum. Which is a valid cast chain. – Vlad274 Oct 07 '15 at 13:10
  • It is not. With every other type you will get a InvalidCastException which makes sense. You cannot cast from base type to derived type if the base type is not a pointer to a derived object. – user2436426 Oct 07 '15 at 13:16
  • You see, I am not trying to nag, the problem is that it's not that trivial. Everybody seems just to say that enums are "magical" int's and somehow it works. But it is not like that, Enum is a class and the classes derived from it should obey the same object oriented principles. But somehow it;s not like that. – user2436426 Oct 07 '15 at 13:20
  • You are incorrect, you can always cast to the base type. EX you can cast pretty much anything to `object`. – Vlad274 Oct 07 '15 at 13:31
  • I didn't said you can't cast to base type. Please read what I said before. I said you can't cast from base to derived if the base type isn't actually the same derived type. – user2436426 Oct 07 '15 at 13:47
0
enum SomeEnum {
    X1,
    X2, 
    X3
}

enum SomeOtherEnum
{
    X1,
    X2,
    X3,
    X4,
    X5
}

public static void SomeFunction(SomeEnum someEnum))

{

    SomeEnum x = SomeEnum.X3; // some dummy init
    try
    {
        x = (SomeEnum) someEnum;
    }
    catch (InvalidCastException) 
    {
        Console.WriteLine("Exception"); // why no exception caught ? why legit cast ?
    }
    Console.WriteLine(x);
}
    private static void Main(string[] args)
    {
        SomeFunction(SomeOtherEnum.X5); // pass a different type than the one in the function
        Console.ReadKey();
    }
shashank
  • 1,133
  • 2
  • 10
  • 24