This lab note is intentionally incomplete.
Question
When is a plain C# enum too small for the job?
The Enumeration class pattern is useful when the code needs a closed set of named values, but the values are more than labels. They may need stable identity, display names, parsing rules, lookup behavior, default handling, validation, or domain-specific behavior.
A plain enum is excellent when the value is truly just a compact symbolic constant. The trouble starts when the surrounding code has to keep explaining what the enum means.
Setup
Draft notes:
- Contrast a plain enum with an
Enumerationbase class. - Explain the pressure that appears in real code: repeated switch statements, duplicated parsing logic, invalid default values, unclear fallbacks, serialization quirks, and scattered display-name behavior.
- Tie this back to
Ifx: the generator can create enumeration types from small enum specifications, but the reason to do that depends on the value of the underlying pattern. - Add the actual
Enumerationclass source once it is available in the current tree.
Observation
Draft notes:
- An enumeration class can make each allowed value an object with a stable
IdandName. - It can centralize lookup by value or name.
- It can provide a single
Allcollection instead of reflection or duplicated lists. - It can keep equality semantics close to the value definition.
- It gives the design somewhere to put behavior if the concept grows.
The important shift is that the value becomes a small domain concept instead of a primitive with comments attached.
Interpretation
Draft notes:
- The pattern is not free. It adds ceremony and another abstraction.
- It becomes worthwhile when the same enum-related rules are being repeated across the codebase.
- It is especially useful when invalid values or ambiguous defaults create real risk.
- It should not be used just because it feels more object-oriented.
The line I want to draw: use a plain enum for simple state. Use an enumeration class when the value has identity, rules, or behavior that deserve a home.
Good Reasons to Use It
Draft notes:
- Stable identity: integer values can remain explicit and meaningful across persistence, messages, or integrations.
- Named values: the name can be part of the model instead of an incidental
ToString()result. - Safer conversion:
FromValueandFromNamecan define one consistent policy. - Discoverability:
Allmakes supported values visible without reflection. - Behavior locality: rules that belong to the value can move closer to the value.
- Reduced drift: repeated enum helper code can be generated or centralized instead of copied.
Risks
Draft notes:
- The pattern can be overused for values that are already simple.
- Default fallback behavior can hide bad input if the caller needs explicit failure.
- Generated enumeration classes must be easy to inspect, test, and reason about.
- The base class must stay small, or every value object inherits more policy than it needs.
Next Experiment
Draft notes:
- Locate or add the actual
Enumerationbase class and document its exact members. - Compare hand-written enumeration classes with generated ones.
- Decide whether failed lookup should return a default, return
null, or expose aTryFrom...method. - Add tests around equality, lookup, ordering, default behavior, and serialization boundaries.
- Revisit
IsRecoverableErrorafter the base type is stable.
Lessons So Far
Draft notes:
- The pattern is strongest when it protects meaning at system boundaries.
- It is weakest when it is used as decorative architecture.
- The generator only makes sense if the underlying
Enumerationclass earns its place.