UnityEnumDict icon indicating copy to clipboard operation
UnityEnumDict copied to clipboard

Support for enums with same-value different-name values.

Open blawnode opened this issue 7 months ago • 6 comments

Heya! Great thanks for your work, I use this package a lot. I know the project is not active, but maybe this could help someone.

I've tried using the package with EnumDict like so: EnumDict<KeyCode, Sprite>. That causes recurring errors: . They were benign for my needs because I don't need the duplicate keys, but this could be more problematic for other uses.

The error:

ArgumentException: An item with the same key has already been added. Key: RightMeta
System.Collections.Generic.Dictionary`2[TKey,TValue].TryInsert (TKey key, TValue value, System.Collections.Generic.InsertionBehavior behavior) (at <17d9ce77f27a4bd2afb5ba32c9bea976>:0)
System.Collections.Generic.Dictionary`2[TKey,TValue].Add (TKey key, TValue value) (at <17d9ce77f27a4bd2afb5ba32c9bea976>:0)
Dev.ComradeVanti.EnumDict.EnumDict`2[TEnum,TData].OnAfterDeserialize () (at ./Library/PackageCache/dev.comradevanti.enum-dict@d1fccb7868/Runtime/EnumDict.cs:84)

And I found a solution thanks to ChatGPT. Seems to work perfectly, with little to no changes.

I propose:

On EnumDict.OnBeforeSerialize():72, I replaced GetEnumValues with GetUniqueEnumValues, which is implemented in EnumUtil, shown below.

EnumUtil.GetUniqueEnumValues():

        // Custom addition by Blawnode.
        // Replaces GetEnumValues().
        // Supports enums like KeyCode, which has different keys (names) with the same value.
        // Requires the addition of Linq, which is already used by EnumDict.
        public static IEnumerable<TEnum> GetUniqueEnumValues<TEnum>() where TEnum : Enum
        {
            return Enum.GetValues(typeof(TEnum))
                .Cast<TEnum>()
                .GroupBy(e => Convert.ToInt32(e))  // Group by raw int value.
                .Select(g => g.First());  // Pick only one name per value.
        }

blawnode avatar Apr 21 '25 09:04 blawnode

Hey there. Thanks for using my package and for your interest in improving it. To be clear, the issue is with situations where an enum uses the same value multiple times, such as in

enum MyEnum {
  A = 0,
  B = 1,
  C = 0
}

correct?

And your proposed solution is to more or less filter out the duplicates. So that would essentially just drop C. I'm not sure I like that as a goto. Let me think about what the alternatives are and get back to you on that.

ComradeVanti avatar Apr 21 '25 10:04 ComradeVanti

If I understand correctly the issue is only related to serializing the enum. There we use it's value to represent the enum key. This causes a duplication error on deserialize.

We could go around this by instead using a string representation of the enum for storage instead. So serialize the key with enum.ToString or Enum.GetName and deserialize with Enum.Parse.

Would you be willing to implement that @blawnode?

ComradeVanti avatar Apr 21 '25 10:04 ComradeVanti

Sorry for the delay! I'm not super active on GitHub and my mail recently.

Serializing the enum by the element's string representation sounds like a good idea on paper! I could give it a spin some time, but I can't promise any finish time.

The issue is indeed about using the same value multiple times like in your example.

And yes, the problem does have to do with serialization. I've had the errors happen when I did [SerializeField] to EnumDict<KeyCode, Sprite>.

But I'd bet that even with serialization put aside, this could still pose as a problem. If I had a non-serialized EnumDict<KeyCode, Sprite>, I could theoretically add the KeyCode.RightMeta AND KeyCode.RightCommand, which would cause said error.

A bit extra context for this RightMeta thingy: It shares the same value as KeyCode.RightCommand and KeyCode.RightApple: They're all 309.

blawnode avatar May 06 '25 12:05 blawnode

Thanks for all the information @blawnode. If you could take care of this issue at some point it would be really great. Feel free to also add a contributors section to the readme and add yourself there :)

ComradeVanti avatar May 06 '25 12:05 ComradeVanti

I've cloned the repository! Before I go ahead and commit stuffs, just to make sure:

But I'd bet that even with serialization put aside, this could still pose as a problem. If I had a non-serialized EnumDict<KeyCode, Sprite>, I could theoretically add the KeyCode.RightMeta AND KeyCode.RightCommand, which would cause said error.

Should I go with my "GetUniqueEnumValues()" idea, or go with your string representation idea?

blawnode avatar Jul 24 '25 16:07 blawnode

Please try my stringapproach or anything similar. Remember that your GetUniqueEnumValues code simply leaves out some of the enum values which may not be expected behavior to most users.

ComradeVanti avatar Jul 24 '25 16:07 ComradeVanti