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

`

8
  • because in your example, your enums are ints! your method just assigns 4 to the value of x within SomeFunction Commented Oct 7, 2015 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? Commented Oct 7, 2015 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) Commented Oct 7, 2015 at 12:25
  • you can cast any int value to enum and vice versa Commented Oct 7, 2015 at 12:25
  • 1
    FYI if you just want to determine if the value is valid for a specific enum use Enum.IsDefined Commented Oct 7, 2015 at 12:27

4 Answers 4

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I am not asking why no compiler error is generated by the compiler, I am asking why the cast is correct ?
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.

2 Comments

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?
No, System.Enum is quite special, and the way defined enums 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..
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.

8 Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.