[draft issue] Allow implicit conversion of enum into underlying type #6989
Unanswered
LWChris
asked this question in
Language Ideas
Replies: 2 comments 6 replies
-
I would really like something like this. I've been using Visual Basic for 25 years and I'm not sure I've ever seen a case where an implicit conversion of an enum to an int caused a bug, but the constant casting in c# is a huge hassle. |
Beta Was this translation helpful? Give feedback.
0 replies
-
This is probably covered by the "extension everything" proposal: #5496 / #5497 public extension UartResultExtensions for UartResult
{
public static implicit operator byte(UartResult value) => (byte)value;
public static implicit operator UartResult(byte value) => (UartResult)value;
} |
Beta Was this translation helpful? Give feedback.
6 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Allow implicit conversion of enum into underlying type
Summary
Allow declaration of
public implicit enum Foo [: UnderlyingType]
which in turn allows members ofFoo
toUnderlyingType
or on thatUnderlyingType
implicitly casts intoImportant: allowing the other direction (casting
UnderlyingType
toenum
) is not part of this original proposal for reasons that I listed under alternatives.Motivation
Especially in serialization and related areas there are often generic functions that require arguments to be passed as native value types such as
int
orbyte
. On the other hand certain transmissible values often have well-known meanings, which calls for them to be declared and organized as anenum
.C# does not allow implicit conversion of an enum to its underlying value type. So if you still want to use the enums, you have to explicitly cast back and forth everywhere:
The
Transmit
case may be made more comfortable with an extension. Write code once, benefit everywhere.For the
Receive
case, creating a like-named extension does not do anything. It has to have a different name to get resolved correctly.For the
==
case there is no "write code once, benefit everywhere" solution available.Even for
Transmit
where a "clean" workaround is possible, it quickly becomes obnoxious to create a cross product of 35 extensions for your 5 enums and 7 methods; this proposal would alleviate this by allowing you to declare your 5 enumsimplicit
and be done. It also removed the obligation to add 5 or 7 more extension methods when the 8th method is added or a 6th enum is introduced.Another half-baked workaround is to use a
static class
withstatic readonly
fields. The downsides of this are that in the debugger you'll only see the value but not the member name, and obviously you can't use thestatic class
as a field type for other places.Detailed design
I'm proposing to create the possibility to add the
implicit
modifier keyword to anenum
declaration. This will allow enum members to be used where the underlying type (or a type that the underlying type can be implicitly cast into) is required:Drawbacks
Compatibility wise: none that I could think of. An existing keyword is introduced in a place where it has been syntactically illegal beforehand, so there can't be any legal code that may conflict with this design proposal.
Usability wise: although I have never found any statement on why enums and their underlying types aren't compatible in C#, I assume there was/is a reason. This would have to be explained and re-evaluated.
If the only argument is "to make it harder to accidentally assign an invalid value", then this argument does not have any relevance for this proposal, because the proposal does not allow assigning the value
5
where theenum
was expected. (On the other hand, in VB.NET even that works and I have never stumbled upon a serious problem with that behavior.)Alternatives
As stated above, this proposal is explicitly only about allowing the "widening" direction enum → underlying type. It might be worth discussing the other way round.
My stance towards this a firm "no" though, since I can see many reasons why that would be much more problematic:
CommandId = 250
instead ofCommandId = CommandId.Reboot
CommandId = myCommand.Value; // oops, I meant .Id
CommandId = config.Value; // obscured whether 'Value' was an arbitrary byte or a "safer" CommandId
return result == UartResult.Ok
- castresult
intoUartResult
, or castUartResult.Ok
intobyte
? This is probably not a big issue; just chose the widening (i.e. second) option like when comparingint
andlong
.If it is still considered, it might be worth discussing about using
in
andout
keywords to selectively allow any direction:implicit enum CommandId : byte
⇒CommandId
⇄byte
(maybe alsoimplicit in out
as well)implicit in enum CommandId : byte
⇒CommandId
→byte
implicit out enum CommandId : byte
⇒CommandId
←byte
If we decide "not now" but want to have this option in the future, we would need the original proposal to be
implicit in
from the start to have no naming conflicts.Alternatively, we can have
implicit enum
now and always meanimplicit in
, and have the option for a future design to be:implicit [in] enum CommandId : byte
⇒CommandId
→byte
implicit out enum CommandId : byte
⇒CommandId
←byte
implicit in out enum CommandId : byte
⇒CommandId
⇄byte
Beta Was this translation helpful? Give feedback.
All reactions