Q: Why casting an enum?

  • Thread starter Visual Systems AB \(Martin Arvidsson\)
  • Start date
V

Visual Systems AB \(Martin Arvidsson\)

Hi!

I have created an enum list like this:

enum myEnum : int
{
This = 2,
That,
NewVal = 10,
LastItm
}

When using the enum, why do i have to cast the value?

int aValue = (int)myEnum.This;

should it not just do with...

int aValue = myEnum.That; ?

Regards

Martin Arvidsson
 
H

Hans Kesting

Visual said:
Hi!

I have created an enum list like this:

enum myEnum : int
{
This = 2,
That,
NewVal = 10,
LastItm
}

When using the enum, why do i have to cast the value?

int aValue = (int)myEnum.This;

should it not just do with...

int aValue = myEnum.That; ?

Regards

Martin Arvidsson

you *should* use
myEnum aValue = myEnum.This;

the enum is a separate type, not just a way to specify a list of integer constants.
So if you want to convert an enum value to an int, you have to cast ...

Hans Kesting
 
F

Frisky

An enum is a class. See the Enum class in the .Net framework.

Normally you do not want to cast an enum to an int. And if you do, you have
to do so explicitly.\

Really, you should avoid assigning values to the enum. The compiler will do
this for you. (If you are trying to make a set of bit flags, be sure to use
the [Flags] attribute. See FlagsAttribute class.)

If is recommended that you would use an enum as follows:

myEnum theEnum = myEnum.That;
if (theEnum == myEnum.LastItm) {
// do something
}

switch (theEnum) {
case: myEnum.This:
// stuff
break;
case: myEnum.That:
// other stuff
break;
// {rest of valid enum values go here}
default:
throw new ArgumentException("Invalid value for theEnum was
specified", "theEnum");
}

Hope this helps...

Frisky
 
J

Jon Skeet [C# MVP]

Frisky said:
An enum is a class. See the Enum class in the .Net framework.

Actually, an enum is a value type. Enum itself is a reference type, but
every enum is a value type.
Normally you do not want to cast an enum to an int. And if you do, you have
to do so explicitly.\
Agreed.

Really, you should avoid assigning values to the enum. The compiler will do
this for you.

That entirely depends on the situation. If the enum is mirroring
existing status codes, for example, you almost certainly *do* want to
assign values.
 
F

Frisky

Jon,

You are absolutley correct, an enum is a value type. It derives from the
System.ValueType. Bad segway into, look up the documentation under
System.Enum.

I don't have to mirror the values for an external system. All I have to do
is make sure I map the external system in and out.

But, it is not a hard fast rule. The example you gave in particular
instances might be the right way to go. I gave the example of using the enum
as a bit flags. Yep, you gotta use values here.

That is why I used the word "avoid".

Fari enough?

Frisky
 
J

Jon Skeet [C# MVP]

Frisky said:
You are absolutley correct, an enum is a value type. It derives from the
System.ValueType. Bad segway into, look up the documentation under
System.Enum.

I don't have to mirror the values for an external system. All I have to do
is make sure I map the external system in and out.

But, it is not a hard fast rule. The example you gave in particular
instances might be the right way to go. I gave the example of using the enum
as a bit flags. Yep, you gotta use values here.

That is why I used the word "avoid".

Fari enough?

I still think "avoid" is a bit too strong without any extra
qualification. I find I need to assign values as often as I don't. It's
probably just a matter of how strong each of us thinks the word
"avoid" is though :)
 
F

Frisky

Actually, it's just my opinion. And it works very well for me and my teams.

I very seldom define any enum with numerical values.

Just goes to show there is more than one way to do things.
 
J

Jon Skeet [C# MVP]

Frisky said:
Actually, it's just my opinion. And it works very well for me and my teams.

I very seldom define any enum with numerical values.

Just goes to show there is more than one way to do things.

I think it's more that it shows that different people have different
applications. There may well be no case where I would assign values and
you wouldn't, but I deal with a lot of situations where the actual
values are important and you don't.

Certainly I'd agree that there's little point in assigning values when
they're not needed - although if the enum is used by an assembly other
than the one in which it's defined, and the assemblies may need to be
changed independently, changing the contents of the enum without
recompiling the other assembly will lead to out-of-date values being
used unless the values are specified and always kept constant.

For instance, if you have Lib.cs:
public enum Bar
{
Hello,
There
}

compiled to Lib.dll

and Test.cs:
using System;

public class Test
{
static void Main()
{
Bar b = Bar.There;
Console.WriteLine (b);
}
}

Compile Test.cs against Lib.dll, and run it - it prints out "There".
Now change Bar.cs to add a new member (Foo) between Hello and There.
Compile just Bar.cs to get a new Lib.dll, rerun Test and it will print
out "Foo". That wouldn't happen if you'd assigned There a value
explicitly and kept it constant when changing the enum. Of course, this
isn't a problem in many situations, but I thought I'd mention it as
another potential reason for explicit numbering.
 
F

Frisky

The enum that is defined in your examlpe is the same as any other interface.
It is open for extension but closed for modification. You must be judicious
in how you modify existing interfaces. Especially if I know the enum is not
directly consumed, but externally through someone else's DLL that I can't
recompile. However, your point is a good one, you should always be careful
how you define things that are used externally.

Had you simply added the value at the bottom of the enum list, the existing
applications would work fine.

Personally, all of the systems we build are built from a highly repeatable
SCM system. We have all of our source and build from scratch at each
interval. This avoids this specific problem. I know many are not this lucky.
If you are shipping external software, you should probably have declared the
enum internal unless it had to be pubic. And what gets marked public is
written in stone.

I use enums for many various external system values. We have lots of
external systems and values. But we always compare name to value. Never
compare value to value. I don't think it is so much the applications, as
just how you have learned to implement your systems.

We have a set of best practices that we follow. This is just one of the
practices. The longer we have used this practice, the more we have found
that there are very few reasons to break the practice.

One more tid bit I'll throw in...

If you define your enum like this:

public enum RegistrationStatus {
Registered = 1,
NotRegistered = 2,
}

and now I write the code:

RegistrationStatus registrationStatus = new RegistrationStatus();

this is a problem. Since enum, as we established earlier, is a value type,
the value you registrationStatus is now undefined. That is, since it is a
value type, the default value is 0, which is not a valid value.
 
J

Jon Skeet [C# MVP]

Frisky said:
The enum that is defined in your examlpe is the same as any other interface.
It is open for extension but closed for modification. You must be judicious
in how you modify existing interfaces. Especially if I know the enum is not
directly consumed, but externally through someone else's DLL that I can't
recompile. However, your point is a good one, you should always be careful
how you define things that are used externally.

Had you simply added the value at the bottom of the enum list, the existing
applications would work fine.

Absolutely - but you may not *want* to put it at the bottom, for some
reason.
Personally, all of the systems we build are built from a highly repeatable
SCM system. We have all of our source and build from scratch at each
interval. This avoids this specific problem. I know many are not this lucky.
If you are shipping external software, you should probably have declared the
enum internal unless it had to be pubic. And what gets marked public is
written in stone.

It doesn't have to be if you specify the values though - you can have a
compatible enum but still put the values wherever you like in the
source code, which can often be very useful if you're grouping the
values into regions.
I use enums for many various external system values. We have lots of
external systems and values. But we always compare name to value. Never
compare value to value. I don't think it is so much the applications, as
just how you have learned to implement your systems.

Not sure what you mean by this... but if you were implementing HTTP
status codes, would you have loads of empty entries, just to get up to
the 50x status codes? Surely not.
We have a set of best practices that we follow. This is just one of the
practices. The longer we have used this practice, the more we have found
that there are very few reasons to break the practice.

Whenever there are external systems which have to be kept in sync in
terms of values, I think you end up with much less brittle software if
everything is explicit.
One more tid bit I'll throw in...

If you define your enum like this:

public enum RegistrationStatus {
Registered = 1,
NotRegistered = 2,
}

and now I write the code:

RegistrationStatus registrationStatus = new RegistrationStatus();

this is a problem. Since enum, as we established earlier, is a value type,
the value you registrationStatus is now undefined. That is, since it is a
value type, the default value is 0, which is not a valid value.

It's not undefined, it's 0. It's a valid value for the variable, it
just doesn't appear in the set of named values. You can get just as
much of a "problem" if you cast an unknown integer value to the enum.

If that's a problem, just don't do that then - start your values as 0
even if you're hardcoding them.
 
F

Frisky

Intellectuals solve problems; geniuses prevent them. ~ Albert Einstein
Jon Skeet said:
Absolutely - but you may not *want* to put it at the bottom, for some
reason.

But you can't. This violates the Open-Close principal. (Software entities
should be open for extension, but closed for modification.)

If you are compiling everything together, this does not make a difference.
It is only for binary compatibility.
It doesn't have to be if you specify the values though - you can have a
compatible enum but still put the values wherever you like in the
source code, which can often be very useful if you're grouping the
values into regions.

I guess what your arguing is that what you mark as public does not have to
be written in stone. But, that's a basic design fundamental anyway. Based on
the Open-Closed principle. This does not matter whether you are talking
about a class, a COM object, or in this case, an Enum. It is a public
interface and cannot be modified. It can only be extended.
Not sure what you mean by this... but if you were implementing HTTP
status codes, would you have loads of empty entries, just to get up to
the 50x status codes? Surely not.

I would simply map the status code to the name and vice-versa. But, the
actual value used by the enum could be any number, and would not matter in
the code. The code that is dependent on the enum (other than this mapping)
is not dependent on a specific implementation of that enum.
Whenever there are external systems which have to be kept in sync in
terms of values, I think you end up with much less brittle software if
everything is explicit.

Actually, I have found that quite the opposite is true. We create an
interface to the external system. The interface is the only piece of code
that knows how to translate code to and from the external system. If the
codes change, I only have one place to change them for conversion.
Internally, its a "who cares".
It's not undefined, it's 0. It's a valid value for the variable, it
just doesn't appear in the set of named values. You can get just as
much of a "problem" if you cast an unknown integer value to the enum.

If that's a problem, just don't do that then - start your values as 0
even if you're hardcoding them.

It is undefined. In the Enum, it was not defined. While it is a valid value
for an Enum, it is not valid for this Enum. If I called a method you were
implementing and sent you a value in an Enum, wouldn't you expect the value
to be one of the defined names? (This is a bug waiting to rear its ugly
head.)

Actually, I thought your argument was that you were using values from an
external system, so that you can map to them. But, if the value has no
significance, and you can just change it to zero at will, why are you
setting the value to begin with? Just let the language do that for you.


Frisky
 
J

Jon Skeet [C# MVP]

Frisky said:
But you can't. This violates the Open-Close principal. (Software entities
should be open for extension, but closed for modification.)

I can't in your way of doing things - but I can add it wherever I like
when I'm assigning values manually, because there's nothing to say that
the order in the source code has to be ascending in value. I can do:

Something = 0,
SomethingIForgotToPutInBefore = 100,
TheOriginalSecondLine = 1

No problem. You can't do that if you don't assign values explicitly.
(You can change to assigning them manually at the point you need to do
the above, of course, so long as you're careful.)
If you are compiling everything together, this does not make a difference.
It is only for binary compatibility.
Yes.


I guess what your arguing is that what you mark as public does not have to
be written in stone.

In what way am I arguing that? In what way is the order in which the
values are defined in source code part of the interface?
But, that's a basic design fundamental anyway. Based on
the Open-Closed principle. This does not matter whether you are talking
about a class, a COM object, or in this case, an Enum. It is a public
interface and cannot be modified. It can only be extended.

Sure. I don't believe that the source code forms part of the interface
though.
I would simply map the status code to the name and vice-versa.

So you'd use a separate map? That seems a bit of a waste to me.
But, the actual value used by the enum could be any number, and would
not matter in the code. The code that is dependent on the enum (other
than this mapping) is not dependent on a specific implementation of
that enum.

Hang on though - a minute ago you were accusing me of breaking things
by changing numbers (which I wasn't). Now you're suggesting that the
"specific implementation" of the enum (by which I assume you mean the
values) shouldn't be relied upon?
Actually, I have found that quite the opposite is true. We create an
interface to the external system. The interface is the only piece of code
that knows how to translate code to and from the external system. If the
codes change, I only have one place to change them for conversion.
Internally, its a "who cares".

Whereas the way I'd do it, you'd still only have one place to change
them for conversion (not that they should be changed, as we've agreed
above) - but that place would also be the definition of the enum. You'd
have one piece of source code doing both jobs, which I believe is more
compact. If an extra code is needed, you only need to add it in one
place rather than two.
It is undefined. In the Enum, it was not defined. While it is a valid value
for an Enum, it is not valid for this Enum. If I called a method you were
implementing and sent you a value in an Enum, wouldn't you expect the value
to be one of the defined names? (This is a bug waiting to rear its ugly
head.)

Not necessarily. In particular, if you assume that and you use the MS
HttpStatusCode enumeration, you may find that a webserver has given you
a value you don't understand. If the value is coming from outside your
control, you *should* be defensive about whether or not it's one that
you understand. You don't need to use a map to do that though.
Actually, I thought your argument was that you were using values from an
external system, so that you can map to them. But, if the value has no
significance, and you can just change it to zero at will, why are you
setting the value to begin with? Just let the language do that for you.

You're the one claiming the value should have no signficance, as I
understand it. I'm saying that the value should have the same
significance inside the code as in the external system, for the sake of
clarity and maintenance. If you get passed a value you don't understand
from the external system, you should react appropriately (whatever that
reaction is for the situation.)
 
F

Frisky

Intellectuals solve problems; geniuses prevent them. ~ Albert Einstein
Jon Skeet said:
I can't in your way of doing things - but I can add it wherever I like
when I'm assigning values manually, because there's nothing to say that
the order in the source code has to be ascending in value. I can do:

Something = 0,
SomethingIForgotToPutInBefore = 100,
TheOriginalSecondLine = 1

No problem. You can't do that if you don't assign values explicitly.
(You can change to assigning them manually at the point you need to do
the above, of course, so long as you're careful.)

But why in the world world would it make a difference where I added a value
in an Enum other than esthetics? (And of course the point we are
discussing.) Assigning them a value only makes them less abstract a more
concreted. In other word, brittle.

And while we all want binary compatibility, who are the few that have to
deliver on this? And if I am one of those few, I am probably faced with the
Open-Closed principle in point of fact on all of the public code I share. I
just a given.
In what way am I arguing that? In what way is the order in which the
values are defined in source code part of the interface?

I am not sure what you were refering to. I did not understand what you meant
by "It doesn't have to be if you specifiy the value though". What is "It"
refering to? I assumed you mean from my previous sentance that the interface
was written in stone.

The enum, if public, is part of you software interface. Interfaces, which
have been around a long time before Java and C# coined the expression, are
any contract between the client and the called code. Right? And as such are
subject to the Open-Closed principle.
Sure. I don't believe that the source code forms part of the interface
though.

Any part of the contract is part of the interface. If you supply a type,
Enum, or other portions of code as public, you are supplying them to fufill
the contract. If you change the enum that your method takes, you
fundamentally have changed that contract. If the client of that code uses a
method that takes the same arguments, including the Enum you changed, then
did the method change, or is it the same? What if the method now does not
throw (or return an error, or null :) like it used to because a value has
been added to the Enum. But, the client code expects that to be an error.
That could be a bug. And one that is hard to detect, because there is no
error now. It was a contract, and the the contract was broken.
So you'd use a separate map? That seems a bit of a waste to me.

Has worked very well for me in the few places where I actually need it. And
its not a data map, but a mapping class.
Hang on though - a minute ago you were accusing me of breaking things
by changing numbers (which I wasn't). Now you're suggesting that the
"specific implementation" of the enum (by which I assume you mean the
values) shouldn't be relied upon?

This is the very point I have been suggesting all along. The code should not
use explicit values of an Enum. (Except the case as aformentioned when you
are using a bit flag, or other compelling reason.)
Whereas the way I'd do it, you'd still only have one place to change
them for conversion (not that they should be changed, as we've agreed
above) - but that place would also be the definition of the enum. You'd
have one piece of source code doing both jobs, which I believe is more
compact. If an extra code is needed, you only need to add it in one
place rather than two.

I think we agree on this. But, are you saying that you too do not use the
value of the Enum after it is assigned? So, you are only using the value as
a means of reading to/from the external or other system that required you to
set them to that value to begin with? Because this is the main part of my
suggestion. I prefer not to assign them or assume anything about their value
(except the bit flag or other compelling case) and use a mapping class to
set them. And from what I think you are saying, this is basically the same,
except you use the actual Enum as you mapping. ???

The only difference, this being the case, is the choice of mapping
technique.
Not necessarily. In particular, if you assume that and you use the MS
HttpStatusCode enumeration, you may find that a webserver has given you
a value you don't understand. If the value is coming from outside your
control, you *should* be defensive about whether or not it's one that
you understand. You don't need to use a map to do that though.

I don't know how this would have anything to do with the code in the Enum.
Sure, I would be defensive that I only understand values in the enumeration.
And perhaps, only a subset of those. But I would not assume that, for
example, the HttpStatusCode.OK necessarily equals 200, even though that may
have been the actual code sent back. I would not compare my enum against a
value of 200. I would have no need to do this. I would check against the
enum name.
You're the one claiming the value should have no signficance, as I
understand it. I'm saying that the value should have the same
significance inside the code as in the external system, for the sake of
clarity and maintenance. If you get passed a value you don't understand
from the external system, you should react appropriately (whatever that
reaction is for the situation.)

Yes, I am claiming that the value has no significance, or at least should
have not significance. But you said you could just change your value to
start at zero. If it does not matter if its zero or twelve, then what does
it matter at all?

And I am claiming that you must make sure that you correctly take a system
that for example passes an int 200 as the return of a status code for and
http service, and map it to HttpStatusCode.OK (assuming that is how you
would like to use it internally). And then, from there on, who cares if it
was status code 200, 501, 400, etc.? Its a HttpStatusCode.OK. Isn't that
enough? Why would I need to know its internal representation?
 
J

Jon Skeet [C# MVP]

Frisky said:
But why in the world world would it make a difference where I added a value
in an Enum other than esthetics? (And of course the point we are
discussing.)

It makes a *huge* difference if you *don't* assign the values
explicitly, as it changes all the other values.
Assigning them a value only makes them less abstract a more
concreted. In other word, brittle.

In my way of doing things, I can add another value anywhere without
changing the rest of the values. In your way of doing things, adding a
value anywhere other than at the end changes at least one value.

In what way is your way *less* brittle than mine?
And while we all want binary compatibility, who are the few that have to
deliver on this? And if I am one of those few, I am probably faced with the
Open-Closed principle in point of fact on all of the public code I share. I
just a given.

We've been bitten in the past by enums which weren't explicitly valued.
The enums were generated from resource files. The resource assembly
needed to be patched, but one of the assemblies which *didn't* need
patching otherwise use the resources. Suddenly all our messages were
coming out completely garbled. (Fortunately it was obvious, so we
caught the problem in time :)

Now the enum generation makes sure that it keeps the same values
forever.
I am not sure what you were refering to. I did not understand what you meant
by "It doesn't have to be if you specifiy the value though". What is "It"
refering to? I assumed you mean from my previous sentance that the interface
was written in stone.

I don't see what you're asking, I'm afraid.

I believe you can have a public interface which *is* written in stone
(extensible - you can add elements) and make life easier for yourself
by explicitly stating those values.

Somehow you took from my post that I was arguing that what you mark as
public does *not* have to be written in stone, and I can't see how that
follows at all.
The enum, if public, is part of you software interface. Interfaces, which
have been around a long time before Java and C# coined the expression, are
any contract between the client and the called code. Right? And as such are
subject to the Open-Closed principle.

Sure. And that (logically) has *nothing* to do with how the source code
is laid out, because the source code is not part of the public
interface. The values of the enums are, but they don't have to be
determined by the order they appear in the source code - that only
happens when you let the compiler assign the values.
Any part of the contract is part of the interface. If you supply a type,
Enum, or other portions of code as public, you are supplying them to fufill
the contract. If you change the enum that your method takes, you
fundamentally have changed that contract. If the client of that code uses a
method that takes the same arguments, including the Enum you changed, then
did the method change, or is it the same? What if the method now does not
throw (or return an error, or null :) like it used to because a value has
been added to the Enum. But, the client code expects that to be an error.
That could be a bug. And one that is hard to detect, because there is no
error now. It was a contract, and the the contract was broken.

I don't think adding values to enums breaks the contract - in my view,
the contract is in terms of not removing things. In the same way, I
don't mind MS adding extra methods to BCL types, but I'd mind if they
removed them.
Has worked very well for me in the few places where I actually need it. And
its not a data map, but a mapping class.

I'm sure it's worked, but that doesn't necessarily mean it was the best
way of doing things.
This is the very point I have been suggesting all along. The code should not
use explicit values of an Enum. (Except the case as aformentioned when you
are using a bit flag, or other compelling reason.)

The code *using* the enum just uses the name - but the enum itself is
responsible for mapping from external integral values to the enum value
as referenced by other code.
I think we agree on this. But, are you saying that you too do not use the
value of the Enum after it is assigned?

Very rarely.
So, you are only using the value as
a means of reading to/from the external or other system that required you to
set them to that value to begin with? Because this is the main part of my
suggestion. I prefer not to assign them or assume anything about their value
(except the bit flag or other compelling case) and use a mapping class to
set them. And from what I think you are saying, this is basically the same,
except you use the actual Enum as you mapping. ???

Sounds like it.
The only difference, this being the case, is the choice of mapping
technique.

Yup - in my case, I only have one place to look, I can add extra things
to the enums without worrying about location, and if I ever *do* use
the value (eg by printing it out somewhere) then it'll be the same
value as the external system uses.

Why add an unnecessary layer of redirection?
I don't know how this would have anything to do with the code in the Enum.
Sure, I would be defensive that I only understand values in the enumeration.
And perhaps, only a subset of those. But I would not assume that, for
example, the HttpStatusCode.OK necessarily equals 200, even though that may
have been the actual code sent back. I would not compare my enum against a
value of 200. I would have no need to do this. I would check against the
enum name.

As you said, you would be defensive that you only understand the values
in the enumeration - which completely blows out of the water your
problem with not having a value of 0 in the enumeration.
Yes, I am claiming that the value has no significance, or at least should
have not significance. But you said you could just change your value to
start at zero. If it does not matter if its zero or twelve, then what does
it matter at all?

It matters if it's easier to write and read the code when there are
fewer layers of indirection.
And I am claiming that you must make sure that you correctly take a system
that for example passes an int 200 as the return of a status code for and
http service, and map it to HttpStatusCode.OK (assuming that is how you
would like to use it internally). And then, from there on, who cares if it
was status code 200, 501, 400, etc.? Its a HttpStatusCode.OK. Isn't that
enough? Why would I need to know its internal representation?

In the case of HttpStatusCode, you can assume that the codes *do* map
directly onto the status codes from the relevant RFC, as that's what
the documentation describes.

Why would I write more code (which could have bugs in) when the
documentation guarantees that I can just cast to the enum?
 
E

Eyal Safran

Jon said:
Very rarely.

Sometimes only the enum itself is sufficient, and sometimes its not.
It really is Application depended.

For example,

enum BaudRates : int
{
BAUD_300 = 300,
BAUD_2400 = 2400,
BAUD_4800 = 4800,
BAUD_9600 = 9600
...
}

if you only need the enum, to represent the mode and not initialize
anything, so only the enum is, as I said, sufficient but if you need to
initialize, a DCB (a struct which is used in serial port
configuration), then you need to cast the enum into value.

Cheers,
Eyal.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Wishes for enum in future builds 1
about enum 3
Problem with casting integer values to enum 4
Casting of Nullable Enums 1
Improve an IEnumerable function 6
Enum Extentions 7
enum is int 2
Casting as an enum type 2

Top