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 Enumeration base 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 Enumeration class 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 Id and Name.
  • It can centralize lookup by value or name.
  • It can provide a single All collection 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: FromValue and FromName can define one consistent policy.
  • Discoverability: All makes 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 Enumeration base 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 a TryFrom... method.
  • Add tests around equality, lookup, ordering, default behavior, and serialization boundaries.
  • Revisit IsRecoverableError after 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 Enumeration class earns its place.