Skip to content

Commit 46a330c

Browse files
CopilotBillWagner
andauthored
Document enum zero conversion dangers and provide validation guidance (#47737)
* Initial plan * Add documentation and examples for enum zero conversion dangers Co-authored-by: BillWagner <[email protected]> * Address review feedback: use ::: syntax, fix explanation, strengthen recommendation Co-authored-by: BillWagner <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: BillWagner <[email protected]>
1 parent 43a78fd commit 46a330c

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

docs/csharp/language-reference/builtin-types/enum.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ You cannot define a method inside the definition of an enumeration type. To add
4242

4343
The default value of an enumeration type `E` is the value produced by expression `(E)0`, even if zero doesn't have the corresponding enum member.
4444

45+
## Implicit conversions from zero
46+
47+
C# allows implicit conversions from the literal value `0` to any enum type, and from `const` values equal to zero. This behavior can lead to unexpected results when an enum doesn't include a member with the value zero:
48+
49+
:::code language="csharp" source="snippets/shared/EnumType.cs" id="SnippetZeroConversions":::
50+
51+
In the preceding example, both `port1` and `port2` are assigned the value `0`, but `GpioPort` has no member with that value. The <xref:System.Enum.IsDefined%2A?displayProperty=nameWithType> method confirms these are invalid enum values.
52+
53+
This implicit conversion exists because the 0 bit pattern is the default for all struct types, including all enum types. However, it can introduce bugs in your code. To avoid these issues:
54+
55+
- You should almost always define a member with value `0` in your enums.
56+
- Use <xref:System.Enum.IsDefined%2A?displayProperty=nameWithType> to validate enum values when converting from numeric types.
57+
- Be cautious when using numeric parameters that might be implicitly converted to enum types.
58+
4559
You use an enumeration type to represent a choice from a set of mutually exclusive values or a combination of choices. To represent a combination of choices, define an enumeration type as bit flags.
4660

4761
## Enumeration types as bit flags

docs/csharp/language-reference/builtin-types/snippets/shared/EnumType.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public static void Examples()
88
{
99
FlagsEnumExample.Main();
1010
EnumConversionExample.Main();
11+
ZeroConversionExample.Main();
1112
}
1213

1314
// <SnippetFlags>
@@ -76,4 +77,50 @@ public static void Main()
7677
}
7778
}
7879
// </SnippetConversions>
80+
81+
// <SnippetZeroConversions>
82+
public enum GpioPort
83+
{
84+
GpioA = 1,
85+
GpioB,
86+
GpioC,
87+
GpioD
88+
}
89+
90+
public class ZeroConversionExample
91+
{
92+
public static void Main()
93+
{
94+
// This compiles without warning but creates an invalid enum value
95+
GpioPort port1 = (GpioPort)0;
96+
Console.WriteLine($"port1: {port1}"); // Output: port1: 0
97+
98+
// This also compiles due to implicit conversion from zero
99+
GpioPort port2 = GetPort(0);
100+
Console.WriteLine($"port2: {port2}"); // Output: port2: 0
101+
102+
// Check if the enum value is valid
103+
bool isValid1 = Enum.IsDefined(typeof(GpioPort), port1);
104+
bool isValid2 = Enum.IsDefined(typeof(GpioPort), port2);
105+
Console.WriteLine($"port1 is valid: {isValid1}"); // Output: port1 is valid: False
106+
Console.WriteLine($"port2 is valid: {isValid2}"); // Output: port2 is valid: False
107+
108+
// Safer approach - validate enum values
109+
if (Enum.IsDefined(typeof(GpioPort), 0))
110+
{
111+
GpioPort safePort = (GpioPort)0;
112+
}
113+
else
114+
{
115+
Console.WriteLine("Value 0 is not a valid GpioPort");
116+
// Handle the invalid case appropriately
117+
}
118+
}
119+
120+
public static GpioPort GetPort(GpioPort port)
121+
{
122+
return port;
123+
}
124+
}
125+
// </SnippetZeroConversions>
79126
}

0 commit comments

Comments
 (0)