proposals/closed-enums.md
Champion issue: https://github.com/dotnet/csharplang/issues/9011
Allow an enum type to be declared closed:
public closed enum Color
{
Red,
Green,
Blue
}
This prevents creation of enum values other than the specified members.
A consuming switch expression that covers all its specified members can therefore be concluded to "exhaust" the closed enum - it does not need to provide a default case to avoid warnings:
Color color = ...;
string description = color switch
{
Red => "red",
Green => "green",
Blue => "blue"
// No warning about missing cases
};
Many enum types are not intended to take on values beyond the declared members, but the language provides no way to express that intent, let alone guard against it happening. For consumers of the type this means that no set of enum values short of the full range of the underlying integral type will be considered to "exhaust" the enum type, and a switch expression needs to include a catch-all case to avoid warnings.
Closed enums provide a way to indicate that the set of enum mebers is complete, and allow consuming code to rely on that for exhaustiveness in switch expressions.
Allow closed as a modifier on enum types.
The following restrictions apply to closed enum types compared to other enum types:
0.Color c = 0; // Ok, all closed enums hve a member corresponding to the value `0`
c = (Color)1; // Ok, the constant `1` corresponds to the member `Green`
c = (Color)10; // Error, there is no member corresponding to the constant `10`
c = (Color)myInt; // Error, `myInt` is not constant
_ = c == Color.Blue; // Ok, `==` does not return a closed enum
_ = Color.Red + 1; // Ok, operands are constant and result corresponds to the member `Green`
_ = c + 1; // Error, operand `c` is not constant
A switch expression that handles all of the members of a closed enum type will be considered to have exhausted that enum type. That means that some non-exhaustiveness warnings will no longer be given:
Color c = ...;
_ = c switch
{
Red => ...,
Green => ...,
Blue => ...
// No warning about non-exhaustive switch
};
On the other hand this also means that it can be an error for the closed enum type to occur as a case after all its members:
Color c = ...;
_ = c switch
{
Red => ...,
Green => ...,
Blue => ...,
Color => ... // Error, case cannot be reached
};
Closed enums are generated with a Closed attribute, to allow them to be recognized by a consuming compiler.
It can be a breaking change to add a closed modifier to an existing enum, or to add an additional member to an existing closed enum. Before publishing a closed enum type, the author needs to consider the long term contract it implies with its consumers.
closed modifier, a closed enum could be designated with a [Closed] attribute.[Flags] enums be supported? If so, they should allow the binary logical (bitwise) operators &, | and ^.