[Draft Issue]: Add defined
pattern for enums
#4657
Replies: 3 comments 6 replies
-
For proper exhaustive enums see #3179
What is the downside of this solution for existing enums compared to this proposal? |
Beta Was this translation helpful? Give feedback.
-
You can get this same behavior by suppressing warning |
Beta Was this translation helpful? Give feedback.
-
What if the enum type that gets loaded at runtime has extra members that weren't there at compile time? Is the difference in behavior between this and if (value is not defined) throw new IEAE("The specified value is not a defined enum member.", ...); |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
This is a Draft Issue. Please comment, and depending on feedback I will hopefully move to an issue soon.
Enum
defined
patternSummary
See #4577 for original idea. We add a new pattern
defined
that is only valid forenum
s. It matches if and only if the enum is exactly the same as any of the members defined on the enum.E.g. Given the enum
enum Directions { North, East, South, West }
, thendirections is defined
is equivalent todirections is Directions.North or Directions.East or Directions.South or Directions.West
.Motivation
#2671 is a highly upvoted issue discussing how the current switch expression exhaustibility check for enums leaves a lot to be desired. Even if you handle all cases for valid enum members, you still get a warning because somebody could cast an arbitrary
int
to an enum. This forces you to add a catch all handler, which means you now don't get a warning if a new enum member is added which you don't explicitly handle.With the
defined
pattern you could do:This will warn only if you haven't handled all members defined on
Directions
. For example if you left outDirections.East
by mistake you would get a switch exhaustibility warning.It's also useful for easy validation. You could now easily validate enums are in the correct range at the entrance to public API's without having to do a large switch / or pattern:
Detailed design
defined
could either be a contextual keyword only if there's no type or constant nameddefined
in scope, or we could take the breaking change and make it a contextual keyword in a pattern unconditionally. Given that both types and constants are usually Uppercase in csharp, the breaking change doesn't seem particularly worrisome.The
defined
pattern is only valid on an enum target. It is not valid onobject
or a type parameter with aSystem.Enum
constraint, or a type implicitly convertible to an enum.Given that the target enum type has
n
membersM1
toMn
, thedefined
pattern is equivalent to the patternM1 or M2 or ... or Mn
. Only members known at compile time are relevant here.The compiler doesn't currently lower a series of or patterns into a jump table where possible, but this is a fairly straightforward optimization to make (it already does this for an or pattern in a switch expression), and should be done anyway. In the worst case though this will have O(n) performance.
Using the 'defined' pattern on a
Flags
enum should result in a warning.Drawbacks
Addition of a new contextual keyword, and added complexity.
Potentially O(n) pattern added, although in practice the compiler should usually be able to generate very efficient code for this, especially when the enum members are left with their default values.
Alternatives
Use an analyzer to warn when a switch doesn't handle all cases of an enum explicitly
Unresolved questions
Best keyword to use.
defined
is only a placeholder.Whether to take the breaking change, or have the meaning of a
defined
pattern depend on whether there are types/constants nameddefined
in scope.Design meetings
Beta Was this translation helpful? Give feedback.
All reactions