Enum Flags not working (selecting wrong value)

Hi

i want to use a System.Flags enum in a component. Also i wrote a custom editor.

This is the Enum.

[System.Flags]
public enum ConnectorGender {
	Neutral = 1,
	Female = 2,
	Male = 4
}

The custom editor reads and writes the value with the following line of code

instance.compatibleGender = (ConnectorGender)EditorGUILayout.EnumMaskField("Genders", instance.compatibleGender);

However when I select a combination of values they are always wrong and when i select everything the value gets -1?

How can i fix this?

Remember that flag enums are internally represented as a series of bits:

public enum ConnectorGender {
    Neutral = 1, //bits: 0000 0001
    Female = 2,  //bits: 0000 0010
    Male = 4     //bits: 0000 0100
}

If you set both Neutral and Male, you’ll see a bit pattern like this:

0000 0101 //Neutral, Male

When Unity sets “nothing”, it sets all bits to 0.

0000 0000 //Nothing (integer value: 0)

When Unity sets “everything”, it sets all bits to 1.

1111 1111 //Everything (integer value: -1)

When you then uncheck a value, it will unset the corresponding bit.

1111 1101 //Everything, minus Female (integer value: -3)
0000 0101 //Same significant bits (integer value: 5)

These seem like totally different values, but remember that the system only really cares about the specific bits it’s working with. You unset the bit for “Female”, but other bits are unchanged.

If you try a custom editor that works with Unity’s own StaticEditorFlags enum, you’ll see this holds true even for their own enums.

Is this a problem? Depends on how you use those values. If all you ever do is check against individual bits, you’ll be fine. If you’re expecting that a particular set of flags will always produce the same value, you might not be.

You can force Unity to unset the extra bits by iterating through them right after the EditorGUILayout call, something like this:

if (instance.compatibleGender < 0) {
	int bits = 0;
	foreach (var enumValue in System.Enum.GetValues(typeof(ConnectorGender))) {
		int checkBit = (int)instance.compatibleGender & (int)enumValue;
		if (checkBit != 0) {
			bits |= (int)enumValue;
		}
	}
	instance.compatibleGender = (ConnectorGender)bits;
}