Skip to main content
Version: 4.0 (next)

Humanize and parse enums and flags

Enum humanization resolves one display label for each member: supported description/display metadata when present, otherwise the humanized member name. Dehumanization also recognizes the raw name, its humanized form, and authored display aliases. Flags enums are decomposed and joined through the active collection formatter.

Example

The executable shows a two-flag value, explicit enum-name and DisplayAttribute source selection, alias dehumanization, and no-match behavior:

Program.cs
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Humanizer;

CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");

var access = Access.Read | Access.Write;

Console.WriteLine($"Flags: {access.Humanize()}");
Console.WriteLine(
$"Enum names: {access.Humanize(LetterCasing.Title, EnumHumanizeSource.EnumName)}");
Console.WriteLine($"Description: {DeliveryState.NeedsReview.Humanize()}");
Console.WriteLine(
$"Display name: {DeliveryState.NeedsReview.Humanize(LetterCasing.Sentence, EnumHumanizeSource.DisplayName)}");
Console.WriteLine($"Parsed alias: {"REVIEW".DehumanizeTo<DeliveryState>()}");
Console.WriteLine(
$"Missing: {"missing".DehumanizeTo<Access>(OnNoMatch.ReturnsNull)?.ToString() ?? "(none)"}");

[Flags]
enum Access
{
[Display(Description = "None")]
None = 0,
[Display(Description = "Can view")]
Read = 1,
[Display(Description = "Can edit")]
Write = 2
}

enum DeliveryState
{
[Display(
Name = "Review required",
Description = "Awaiting reviewer",
ShortName = "Review")]
NeedsReview,
[Display(Name = "Waiting in queue")]
QueuedItem
}
Output
Flags: Can view and Can edit
Enum names: Read and Write
Description: Awaiting reviewer
Display name: Review required
Parsed alias: NeedsReview
Missing: (none)

Choose metadata and casing

Humanizer prefers supported description/display metadata before deriving words from the member name. That chosen value is also the member's dehumanization label. LetterCasing changes only labels derived from the member name; authored metadata preserves its exact casing. Configurator.UseEnumDescriptionPropertyLocator can select a custom description-like property globally and must run before enum metadata is cached.

Select the humanization source

Pass both LetterCasing and EnumHumanizeSource when the default metadata precedence is not the desired presentation:

  • Default preserves the existing precedence. A DisplayAttribute uses its Description, then its Name, then the member name. Without that attribute, a configured description-like property is checked before the member name.
  • EnumName derives text from the member name and applies the requested casing.
  • DisplayName uses DisplayAttribute.Name.
  • DisplayDescription uses DisplayAttribute.Description.
  • DisplayShortName uses DisplayAttribute.ShortName, then its Name.

If selected display metadata is missing, Humanizer falls back to the humanized enum member name and applies the requested casing. Authored display metadata preserves its casing, and localized DisplayAttribute getters are honored. For flags, the selected source and fallback apply independently to each constituent before the labels are joined.

Source selection intentionally uses the Humanize(LetterCasing, EnumHumanizeSource) overload; there is no source-only overload, so existing calls such as Humanize(default) and Humanize(0) keep their prior meaning. An undefined EnumHumanizeSource throws ArgumentOutOfRangeException. Explicit source selection reads only the chosen DisplayAttribute property, so an unrelated invalid localized property does not break the call. A custom description-property locator affects the default path, not the explicitly selected DisplayAttribute sources. It does not change dehumanization aliases or their collision rules.

Parse accepted aliases

DehumanizeTo<TEnum> recognizes the raw member name, its humanized form, and DisplayAttribute name, description, and short-name values. It also recognizes a configured description attribute value when that value becomes the member's authored description. Matching is case-insensitive, including for flags, but does not trim whitespace.

Handle missing input

The default DehumanizeTo<TEnum> throws NoMatchFoundException. Pass OnNoMatch.ReturnsNull to the nullable generic overload when an unknown label is expected.

Format flags

Known nonzero flags are humanized and joined using the current UI culture. A defined zero member uses its label. A value containing only unknown bits humanizes to an empty string.

Prefer unambiguous aliases and generic overloads

Aliases should be unambiguous even though matching is case-insensitive. A current humanized representation takes precedence over a supplemental alias when labels collide; collisions among supplemental aliases retain the later enum value in unsigned numeric order. Prefer the generic enum overloads. Runtime enum humanization and the runtime Type dehumanization overload use reflection and are annotated with RequiresDynamicCode and RequiresUnreferencedCode; they are not the safe default for trimmed or Native AOT applications.