Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Best way to get infos about KeyNotFoundException: The given key was not present in the dictionary.

Discussion in 'Scripting' started by rainboww, Feb 21, 2017.

  1. rainboww

    rainboww

    Joined:
    Jan 5, 2017
    Posts:
    125
    Hello,
    i like to have a way to find out what key was not found and write it to a logfile when i get a KeyNotFoundException: The given key was not present in the dictionary.
     
  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,340
    I assume you're doing something like:

    Code (csharp):
    1. string data = myDict[5];
    Replace it with:

    Code (csharp):
    1. string data;
    2. if (!myDict.TryGetValue(5, out data)) {
    3.     Debug.LogError("myDict doesn't have the value " + 5 + ", I can write that to a log file!");
    4. }
    5. else {
    6.     //do whatever you were planning to do
    7. }
    TryGetValue assigns returns true if the key exists. It also assigns to the out variable, so you can use it. Always use TryGet if there's a possibility that the key doesn't exist.
     
    Suddoha likes this.
  3. rainboww

    rainboww

    Joined:
    Jan 5, 2017
    Posts:
    125
    I understand that this would have to be placed everywhere where i want to access the dictionary?
    I think it will be on some places right thankyou, but I still would like to have something where i dont need to change my code much.

    my dictionary custom class looks like this:

    Code (CSharp):
    1.  
    2.         [Serializable]
    3.         public class d1 : Dictionary<string, string> {
    4.  
    5.             public d1() {
    6.             }
    7.         }
    Sadly do i not know enough about custom classes to change it myself.
     
  4. rainboww

    rainboww

    Joined:
    Jan 5, 2017
    Posts:
    125
    I found something:

    http://rextester.com/YKWBI65251

    Code (CSharp):
    1. //Extended dictionary
    2.  
    3. using System;
    4. using System.Collections.Generic;
    5. using System.Linq;
    6. using System.Text.RegularExpressions;
    7.  
    8. namespace Rextester
    9. {
    10.     public class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    11.     {
    12.         public TValue this[TKey key]
    13.         {
    14.             get
    15.             {
    16.                 TValue val;
    17.                 if(base.TryGetValue(key, out val))
    18.                 {
    19.                     return val;
    20.                 }
    21.                 else
    22.                 {
    23.                     throw new KeyNotFoundException(string.Format("The given key ({0}) was not present in the dictionary.", key));
    24.                 }
    25.             }
    26.             set
    27.             {
    28.                 base[key] = value;
    29.             }
    30.         }
    31.     }
    32.     public class Program
    33.     {
    34.         public static void Main(string[] args)
    35.         {
    36.             //Dictionary<string, string> dic = new Dictionary<string, string>()
    37.             //{
    38.             //    {"a", "b"}
    39.             //};
    40.             MyDictionary<string, string> dic = new MyDictionary<string, string>()
    41.             {
    42.                 {"a", "b"}
    43.             };
    44.            
    45.             Console.WriteLine(dic["aa"]);
    46.         }
    47.     }
    48. }
     
  5. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    You shouldn't change the behaviour. The way to do it with that approach would be to derive from Dictionary<TKey, TValue> like you've already done and hide the inherited indexer ( [ ] ) using the "new" keyword.

    But I (personally) strongly recommend to not do it, as it changes the behaviour in an unexpected way. So if you were to reference your custom dictionary as a normal dictionary, the indexer would suddenly act differently.

    The other way would be to wrap a dictionary and define your own behaviour.

    But this might also confuse you in the future if you use both, normal dictionaries and your custom dictionary, as you always need to keep that implementation detail in mind.

    This being said, you should follow the given advice (by @Baste) and use the appropriate way to access a dictionary's values.

    Off-topic, but related:
    The same applies to adding a value. There's a tiny but important difference between Add() and using the indexer ( [ ] ). One (the indexer) allows to add & replace values for a given key, the other one (the Add() method) only allows to add and throws an exception if the specified key does already exist.
     
  6. rainboww

    rainboww

    Joined:
    Jan 5, 2017
    Posts:
    125
    I tried it already my app still works .which has some 50-100 references to the custom dictionarys.

    Well i am not sure about this how would it look like?

    Essentially i need it for debug while i like to keep it if there is an issue i could remove it in the final product.

    I will not rewrite some 100 lines to get a new debug feature. I could do that only at few parts of the app.
     
  7. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,554
    Have you tried attaching the debugger to unity (in VisualStudio or MonoDevelop, select 'attach to unity'), put in some break points and run your project.

    Furthermore, when unity prints an exception, it includes the stack trace. The stack trace will tell you the specific line of code it happened at, so you can put the break point at that specific line.

    In the unity console, where the exception shows, click to highlight it expanding the full text of the exception. It's look something like:

    In this case you can see the error occured on the function 'OnStartOrEnable' at line '36' of my script called 'OverheadCamera'.


    Lastly:
    It's not a new debug feature (it's not a debug feature at all). It's effective well formed code to use the TryGetValue method of a dictionary when you are accessing it with volatile keys that may or may not exist in the dictionary.

    We as programmers often end up having to rewrite code sometimes because our early version is error prone... it's just a fact of writing code.

    Anyways, you want a new debug feature... it exists, I already described it. Use the built in debugger!
     
    Last edited: Feb 22, 2017
    Suddoha likes this.