Context
All generated IEnum classes (standalone enums via modelEnum.mustache and inner TypeEnum classes via modelInnerEnum.mustache) implement GetHashCode using the default case-sensitive string hash:
public override int GetHashCode() => Value?.GetHashCode() ?? 0;
However, Equals and the ==/!= operators use StringComparison.OrdinalIgnoreCase:
public override bool Equals(object? obj) =>
obj is Result other && string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
This violates the fundamental hash/equality contract: objects that compare equal must produce the same hash code. As a result, "valid" and "VALID" are considered equal by Equals but produce different hash codes, causing incorrect behaviour when IEnum instances are used as dictionary keys or in hash sets.
Affected generated types include all standalone IEnum classes (e.g. Result, LimitStatus, Scope) and all inner TypeEnum classes (e.g. CheckoutThreeDS2Action.TypeEnum, CheckoutDelegatedAuthenticationAction.TypeEnum).
Proposed Change
Fix GetHashCode in both modelEnum.mustache and modelInnerEnum.mustache to use a case-insensitive comparer:
public override int GetHashCode() =>
StringComparer.OrdinalIgnoreCase.GetHashCode(Value ?? string.Empty);
This matches the comparer used by Equals and handles null consistently.
Benefit
Restores the hash/equality contract, making IEnum instances safe to use as dictionary keys or in hash sets, and eliminates a latent source of hard-to-debug lookup failures.
Notes
Low-severity latent bug
- Narrow trigger condition: It only manifests when IEnum instances are used as dictionary keys or in hash sets, AND the casing differs between two values that should be considered equal (e.g., "valid" vs "VALID"). In normal SDK usage, enum values come from the API with consistent casing, so mismatches are unlikely.
- Hard to hit in practice: Users rarely use TypeEnum instances as dictionary keys. The typical usage pattern is comparison via
==, which works correctly.
- When triggered, the effect is subtle: A hash set/dictionary lookup would silently fail to find a matching key, leading to hard-to-debug "missing entry" bugs -- not crashes or data corruption.
In summary: it's a correctness violation of the .NET hash/equality contract that should be fixed for hygiene, but it's unlikely to affect real-world users with the current SDK usage patterns.
Context
All generated
IEnumclasses (standalone enums viamodelEnum.mustacheand innerTypeEnumclasses viamodelInnerEnum.mustache) implementGetHashCodeusing the default case-sensitive string hash:However,
Equalsand the==/!=operators useStringComparison.OrdinalIgnoreCase:This violates the fundamental hash/equality contract: objects that compare equal must produce the same hash code. As a result,
"valid"and"VALID"are considered equal byEqualsbut produce different hash codes, causing incorrect behaviour when IEnum instances are used as dictionary keys or in hash sets.Affected generated types include all standalone IEnum classes (e.g.
Result,LimitStatus,Scope) and all innerTypeEnumclasses (e.g.CheckoutThreeDS2Action.TypeEnum,CheckoutDelegatedAuthenticationAction.TypeEnum).Proposed Change
Fix
GetHashCodein bothmodelEnum.mustacheandmodelInnerEnum.mustacheto use a case-insensitive comparer:This matches the comparer used by
Equalsand handlesnullconsistently.Benefit
Restores the hash/equality contract, making IEnum instances safe to use as dictionary keys or in hash sets, and eliminates a latent source of hard-to-debug lookup failures.
Notes
Low-severity latent bug
==, which works correctly.In summary: it's a correctness violation of the .NET hash/equality contract that should be fixed for hygiene, but it's unlikely to affect real-world users with the current SDK usage patterns.