Home > Net >  Operations over dictionary-key without System.Collections.Generic.KeyNotFoundException
Operations over dictionary-key without System.Collections.Generic.KeyNotFoundException

Time:10-29

I have a simple dictionary call result:

Dictionary<String,String> results=new();
results["a"]="a";
results["b"]="b";
results["c"]="c";

To simplify the example my dictionary only contains 3 letter keys a,b,c. But sometimes it will not contain one of this values or even none, (it will always be initiallized). suppose this situation:

Dictionary<String,String> results=new();
if(anyconditionA) results["a"]="a";
if(anyconditionB)results["b"]="b";
if(anyconditionC)results["c"]="c";

So each time i want to operate with this dictionary i have to check the key value: var test= results["a"]; -> throws System.Collections.Generic.KeyNotFoundException if anycontitionA is not true. so to solve this i do:

if(results.ContainsKey("a"){
  someOperation(results["a"]);
}

so if i have many values code looks like:

if(results.ContainsKey("a"){someOperation(results["a"]);}
if(results.ContainsKey("b"){... stuff}
if(results.ContainsKey("c"){... stuff}
if(results.ContainsKey("..."){... stuff}
if(results.ContainsKey("d"){someOperation(results["d"]);}

¿Is there a propper way to do this in one statement i mean check and do the operation if exists or i have to test every time that value exists? (like do with null operator in a list something like results[a]?.someOperation() ) Thanks!

CodePudding user response:

If you find yourself doing this a lot and you want to simplify the calling code, you could write an extension method:

public static class DictionaryExt
{
    public static bool DoIfExists<TKey, TValue>(this Dictionary<TKey, TValue> self, TKey key, Action<TValue> action)
    {
        if (!self.TryGetValue(key, out var value))
            return false;

        action(value);
        return true;
    }
}

Then you could write code like this:

results.DoIfExists("a", someOperation);

results.DoIfExists("b", value => Console.WriteLine("Doing stuff with "   value));

results.DoIfExists("c", value =>
{
    Console.WriteLine("Doing stuff with "   value);
    Console.WriteLine("This uses multiple lines.");
});

I'm really not sure this is worth it (I don't like overuse of extension methods), but that's a matter of opinion!

In my opinion the third example above obfuscates the code and would be better written as:

if (results.TryGetValue("c", out var value))
{
    Console.WriteLine("Doing stuff with "   value);
    Console.WriteLine("This uses multiple lines.");
}

but the first example results.DoIfExists("a", someOperation); is arguably somewhat simpler than:

if (results.TryGetValue("a", out var value))
    someOperation(value);

This is a marginal improvement, and I personally wouldn't bother. It's up to you!

CodePudding user response:

You've got the "maybe don't call an operation that takes the value, if the key is not in the dictionary" from Matthew Watson, but at the end of your question you asked about a slightly different problem

¿Is there a propper way to do this in one statement i mean check and do the operation if exists or i have to test every time that value exists? (like do with null operator in a list something like results[a]?.someOperation() ) Thanks!

If the operation is a method on the value in the dictionary then sure, you can use ?. to prevent a null ref on a non existent value:

        var dictionary = new Dictionary<int, StringBuilder>();

        dictionary.GetValueOrDefault(1)?.AppendLine("hello");

GetValueOrDefault is implemented as an extension method and is a .net core 2.2 thing. There are nuget packages that make it available for older versions, or you can write it yourself as an extension possibly adapting it from the netcore source and putting it into your app:

    public static TValue? GetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
    {
        return dictionary.GetValueOrDefault(key, default!);
    }

    public static TValue GetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
    {
        if (dictionary == null)
        {
            throw new ArgumentNullException(nameof(dictionary));
        }

        TValue? value;
        return dictionary.TryGetValue(key, out value) ? value : defaultValue;
    }
  • Related