C# Dictionary - The given key was not present in t

2019-02-23 17:19发布

问题:

I'm currently trying to load game objects from a Tiled (Tiled map editor) map file into a game engine I'm making in C#. I'm using TiledSharp (Link to github here). It uses a dictionary to hold properties about each individual tile (or 'game object') I'm trying to load. But for some reason I get an error when I loop through the properties, and I also get an error if I check if it's null

Here's a snippet of the code I'm using:

for (int l = 0; l < tmxMap.Tilesets[k].Tiles.Count; l++)
    // This line throws an error
    if (tmxMap.Tilesets[k].Tiles[l].Properties != null)
        // and if I remove the above line, this line throws an error
        for (int m = 0; m < tmxMap.Tilesets[k].Tiles[l].Properties.Count; m++)

The error I get says The given key was not present in the dictionary. But... I'm not even checking for a key.

Am I missing something?

Any help would be appreciated.

回答1:

The error I get says The given key was not present in the dictionary. But... I'm not even checking for a key.

Yes you are checking for a key. This is your code:

if (tmxMap.Tilesets[k].Tiles[l].Properties != null)

You are checking for Tilesets with key k and then checking Tiles with key l. If the Tilesets does not contain an item with key k, you will get that error. The same is true for Tiles with key l.

You can do the following when working with dictionaries:

Option 1

The lookup is performed twice: once to see if the item exists, and then a second time to get the value:

var items = new Dictionary<string, string>();
items.Add("OneKey", "OneValue");
if(items.ContainsKey("OneKey"))
{
    var val = items["OneKey"];
}

Option 2

And here is another approach where the lookup is performed once:

string tryVal;
if (items.TryGetValue("OneKey", out tryVal))
{
    // item with key exists so you can use the tryVal
}


回答2:

As far as I can see in your code I think that Tiles is a Dictionary and when you try to iterate by tmxMap.Tilesets[k].Tiles[l] it throws error because it searches for key l, not for the l-element.

You can try tmxMap.Tilesets[k].Tiles[tmxMap.Tilesets[k].Tiles.Keys.ElementAt(l)]



回答3:

You are trying to get a value based on keys k,l.

if (tmxMap.Tilesets[k].Tiles[l].Properties != null) statement is basically getting the value corresponding to the k key in Tilesets dictionary. If Tilesets dictionary doesn't contain a value for the key k, an exception will be thrown. Also if there is no value corresponding to the l key, in Tiles dictionary, exception will be thrown.

You can use TryGetValue extension method, which will give you the value if the item was found.

    TileSet ts = null;

    if(tmxMap.Tilesets.TryGetValue(k, out ts)
    {
       for (int l = 0; l < ts.Tiles.Count; l++)
       { 
          Tiles tl = null;

          if(ts.TryGetValue(l,out tl)
          {
            if (tl.Properties != null)
            {
              for (int m = 0; m < tl.Properties.Count; m++)
              {
               //Do something
              }
            }
          }
        }
     }