2

I am sorry if this question is being asked because i missed something incredibly basic.

I am gettingKeyNotFoundException with the error:

The given key was not present in the dictionary from Unity for a search for a Dictionary Key.

Example code is added below.

When I press GET DATA button on GUI it is working fine. But it is giving KeyNotFoundException when I press GET DATA CAST button on GUI.

What I am missing? Any suggested changes that I need to make in code

I inserted data into Dict, sorry I missed that to post here Class

[System.Serializable]
public sealed class AnimName
{
    public static readonly AnimName IDLE = new AnimName("IDLE");

    public AnimName(string value)
    {
        Value = value;
    }
    public string Value { get; private set; }
}

Dict and Code:

Dictionary<AnimName, AnimData> KeyValueData = new Dictionary<AnimName, AnimData>();

//This is called once

Start(){
KeyValueData.Add(AnimName.IDLE, new AnimData(new Vector3(-0.09f, -0.02f, -0.25f), new Vector3(-41.866f, 386.781f, -524.68f), new Vector3(-0.028f, 0.027f, 0.13f), new Vector3(18.724f, 19.477f, -32.435f), 0.3f));
}


void OnGUI()
{
    if (GUI.Button(new Rect(10, 10, 150, 100), "GET DATA"))
    {
        Debug.Log(KeyValueData [AnimName.IDLE]);
    }
    if (GUI.Button(new Rect(200, 10, 150, 100), "GET DATA CAST"))
    {
        AnimName a = new AnimName("IDLE");
        Debug.Log(KeyValueData [a]);
    }

}
djkpA
  • 1,224
  • 2
  • 27
  • 57
  • Which line of code gives you error? Can you share the code of "GET DATA" click and "GET DATA CAST" click? And where the "KeyValueData" is being populated. – Chetan Aug 04 '17 at 10:56
  • 1
    Have you actually put something into `KeyValueData` with a key of `[AnimName.IDLE]` ? Otherwise the dictionary appears - from your code - to be empty hence the error message :) – Stephen Byrne Aug 04 '17 at 10:56
  • Cause your dictionary looks empty to me – Rahul Aug 04 '17 at 10:57
  • Honestly, though, does the error message not tell you exactly what's wrong? – Kenneth K. Aug 04 '17 at 10:57
  • @ChetanRanpariya, it's already posted in question – Rahul Aug 04 '17 at 10:57
  • Overwrite `Equals` and `GetHashCode` in your `AnimName` type. Otherwise `new AnimName("foo")` and `new AnimName("foo")` will refer to two different objects so they will be two *different* keys in a dictionary. – poke Aug 04 '17 at 10:59
  • @KennethK.: It doesn't because I assume the OP expects `AnimName.Idle` to be the same as `new AnimName("IDLE")`. The OP believes that the entry *is* in the dictionary. – Chris Aug 04 '17 at 11:00
  • @Chris There was no initialization shown when I posted. So to me it looked like it was an empty dictionary to begin with. – Kenneth K. Aug 04 '17 at 11:03
  • @KennethK.: Not sure the relevant code changed. He said that GET DATA worked and GET DATA CAST didn't. Assuming that this referred to the two if statements the OP was saying that `KeyValueData [AnimName.IDLE]` worked and `KeyValueData [a]` didn't. From this we can infer that `AnimName.IDLE` is a valid key. No matter though. – Chris Aug 04 '17 at 11:09

2 Answers2

3

You have to implement a custom EqualityComparer that compares the names. Passing it to the dictionary's constructor will solve the problm. Otherwise, the dictionary will use the references for comparison which are not equal in your case.

class AnimNameEqualityComparer: EqualityComparer<AnimName>
{
    public override bool Equals(AnimName a1, AnimName a2)
    {
         return a1.Value.Equals(a2.Value)
    }

    public override int GetHashCode(AnimName a)
    {
        return a.Value.GetHashCode();
    }
}

Use the comparer when creating the dictionary:

Dictionary<AnimName, AnimData> KeyValueData = new Dictionary<AnimName, AnimData>(new AnimNameEqualityComparer());
JanDotNet
  • 3,746
  • 21
  • 30
2

a in the second is not the same object as AnimName.IDLE. If you think about it you have explicitly created a new object. By default it is using reference equality which will only match if it is the exact same instance of the object.

If you want to be able to crea0te new AnimName objects like this and have them be considered equal to previously created ones you need to add code to your AnimName class to tell it what is equal and what is not. http://www.aaronstannard.com/overriding-equality-in-dotnet/ seems to be a good starting point for doing this.

Alternatively just stick with what you already have of using static readonly variables to cover all the possibilities you want. This does of course rely on you knowing all the possible values at compile time.

Chris
  • 27,210
  • 6
  • 71
  • 92