diff --git a/docs/csharp/language-reference/builtin-types/enum.md b/docs/csharp/language-reference/builtin-types/enum.md index 2fb7ebfa3eea2..236c8958cc45a 100644 --- a/docs/csharp/language-reference/builtin-types/enum.md +++ b/docs/csharp/language-reference/builtin-types/enum.md @@ -42,6 +42,20 @@ You cannot define a method inside the definition of an enumeration type. To add 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. +## Implicit conversions from zero + +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: + +:::code language="csharp" source="snippets/shared/EnumType.cs" id="SnippetZeroConversions"::: + +In the preceding example, both `port1` and `port2` are assigned the value `0`, but `GpioPort` has no member with that value. The method confirms these are invalid enum values. + +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: + +- You should almost always define a member with value `0` in your enums. +- Use to validate enum values when converting from numeric types. +- Be cautious when using numeric parameters that might be implicitly converted to enum types. + 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. ## Enumeration types as bit flags diff --git a/docs/csharp/language-reference/builtin-types/snippets/shared/EnumType.cs b/docs/csharp/language-reference/builtin-types/snippets/shared/EnumType.cs index 4016a3a6f3d4d..0b638c3cbc8cf 100644 --- a/docs/csharp/language-reference/builtin-types/snippets/shared/EnumType.cs +++ b/docs/csharp/language-reference/builtin-types/snippets/shared/EnumType.cs @@ -8,6 +8,7 @@ public static void Examples() { FlagsEnumExample.Main(); EnumConversionExample.Main(); + ZeroConversionExample.Main(); } // @@ -76,4 +77,50 @@ public static void Main() } } // + + // + public enum GpioPort + { + GpioA = 1, + GpioB, + GpioC, + GpioD + } + + public class ZeroConversionExample + { + public static void Main() + { + // This compiles without warning but creates an invalid enum value + GpioPort port1 = (GpioPort)0; + Console.WriteLine($"port1: {port1}"); // Output: port1: 0 + + // This also compiles due to implicit conversion from zero + GpioPort port2 = GetPort(0); + Console.WriteLine($"port2: {port2}"); // Output: port2: 0 + + // Check if the enum value is valid + bool isValid1 = Enum.IsDefined(typeof(GpioPort), port1); + bool isValid2 = Enum.IsDefined(typeof(GpioPort), port2); + Console.WriteLine($"port1 is valid: {isValid1}"); // Output: port1 is valid: False + Console.WriteLine($"port2 is valid: {isValid2}"); // Output: port2 is valid: False + + // Safer approach - validate enum values + if (Enum.IsDefined(typeof(GpioPort), 0)) + { + GpioPort safePort = (GpioPort)0; + } + else + { + Console.WriteLine("Value 0 is not a valid GpioPort"); + // Handle the invalid case appropriately + } + } + + public static GpioPort GetPort(GpioPort port) + { + return port; + } + } + // }