Skip to main content

EnumValues

A table of values per enum member, filled in the Inspector instead of code.

Quick start​

Before — fields and switchAfter — FastTools
[SerializeField]
private float _default = 1f;
[SerializeField]
private float _fire = 1.5f;

public float GetMultiplier(
DamageType type) => type switch
{
DamageType.Fire => _fire,
_ => _default
};
[SerializeField]
private EnumValues<DamageType, float>
_multipliers;

public float GetMultiplier(
DamageType type) =>
_multipliers.GetValue(type);

GetValue returns the value from a matching table row, or Default Value if no row matches.

The Multipliers table in the Inspector: a Fire row of 1.5 and Default Value 1The Multipliers table in the Inspector: a Fire row of 1.5 and Default Value 1

Filling in the Inspector​

For an enum without [Flags], set the shared value in Default Value and add rows for members that need a different value.

Populate Missing Enum Members in the table header's context menu appends rows for missing enum members and copies Default Value into them.

For [Flags], only declared enum members are added automatically. For example, if the enum declares FireAndIce = Fire | Ice, the command adds a separate row with the key FireAndIce. Combinations without a name can be added manually.

Populate Missing Enum Members in the Multipliers tablePopulate Missing Enum Members in the Multipliers table

note

A row added to an empty table shows <None> and is skipped with a Console error until you pick a member.

Choosing a variant​

DifferenceEnumValues<TEnum, TValue>EnumValues<TValue>
Where the enum is pickedThe TEnum argumentThe table header in the Inspector
Key in GetValue and foreachTEnumSystem.Enum
Boxing in GetValueNoneThe key is boxed
A key of another enumDoes not compileReturns Default Value
  • Table values are configured in the Inspector and are read-only from code.
  • TValue is any type Unity serializes.

With EnumValues<TValue>, the multiplier field is declared as EnumValues<float>, and DamageType is selected in the table header:

[SerializeField]
private EnumValues<float>
_multipliers;

DamageType in the type selector of the Multipliers headerDamageType in the type selector of the Multipliers header

  • Selecting an enum is required: if the field is empty, the Inspector shows Required type is not set. The required field check also checks this field.
  • The first access to a table with an empty enum field logs a Warning to the Console. Calls to GetValue return Default Value.

Lookup rules​

A row's key is its selected enum member. If several rows have the same key, the topmost row is used. Enum members with the same numeric value also count as one key: for example, declaring Frost = Ice gives both names the same value.

Inspector rows, top to bottomGetValue argumentReturned value
Fire → 0.9
Fire → 0.5
DamageType.Fire0.9
Ice → 0.5DamageType.Frost0.5

Flags​

[Flags]
public enum DamageType
{
None = 0,
Fire = 1,
Ice = 2,
Frost = Ice,
FireAndIce = Fire | Ice,
Poison = 4
}

[SerializeField]
private EnumValues<DamageType, float>
_multipliers;

For [Flags], lookup has two stages:

  1. First, look for an exact match: a row whose key contains exactly the same flags as the argument.
  2. If there is no exact match, use the topmost row whose flags are all present in the supplied value.

Suppose Default Value is 0 and the Inspector table is filled as follows:

OrderKeyValue
1Fire0.9
2Ice0.5
3FireAndIce0.3
4None1

For this table, GetValue returns these results:

ArgumentValueWhy
Fire | Ice0.3Exact match with FireAndIce (row 3): both flags match
Fire | Ice | Poison0.9The argument contains all the flags of rows 1, 2 and 3. With no exact match, row 1 is used
Ice | Poison0.5Ice (row 2) matches. Rows 1 and 3 also need Fire, which is absent from the argument
Poison0No matching row — Default Value
None1A zero key matches only a zero argument
note

Moving the FireAndIce row above Fire makes a call for Fire | Ice | Poison return 0.3. Row order determines priority when there is no exact match.

A row whose value equals Default Value still participates in lookup. Adding a Fire | Poison row with value 0 makes a call for that combination return 0 by exact match, instead of 0.9 from the Fire row.

Equals()​

The table method checks whether a key matches a request without reading values:

var request =
DamageType.Fire | DamageType.Ice;
var key = DamageType.Fire;
_multipliers.Equals(request, key);
RequestKeyResult
DamageType.Fire | DamageType.IceDamageType.Firetrue
DamageType.FireDamageType.Fire | DamageType.Icefalse
DamageType.Fire | DamageType.IceDamageType.Nonefalse
DamageType.NoneDamageType.Nonetrue

In EnumValues<TValue>, Equals returns false if either argument has a different enum type from the one selected in the Inspector.

Enumerating rows​

var total = 0f;
foreach (var entry in _multipliers)
total += entry.Value;

Default Value and rows with unresolved keys are not yielded. After the first access initializes the keys, a direct foreach over the table does not allocate. Iteration through IEnumerable boxes the enumerator.

When the enum changes​

Keys are stored by member name:

ChangeResult
Members reordered or their numeric values changedRows remain bound to names. Changing aliases or flag bit patterns can change lookup results
A member renamed or deletedIts row shows <Missing Ice> and is skipped with a Console error; restore the name and the row works again
The enum renamed or moved to another namespace or assemblyEnumValues<TEnum, TValue> works as before; EnumValues<TValue> returns Default Value and logs an error until the enum is picked again
Another enum picked in EnumValues<TValue>The keys are kept: pick the previous enum back and the rows work again

Package sample​

Tiles and footprints take their colour from EnumValues<SurfaceType, Color>, and the speed multiplier from an EnumValues<float> with a [Flags] enum picked in the Inspector: EnumValues.

The trail colour and walking speed change as the character crosses onto another surface.The trail colour and walking speed change as the character crosses onto another surface.