user441521 user441521 - 1 year ago 74
C# Question

Checking a key exists in a Dictionary of Action's before trying to call it using ForEach

I have a dictionary where the key is a string and the value is an Action. I setup mapping of string keys to functions. I then have a list that I call .ForEach() on and inside this I use a value in the list as the key and then call the function associated with it. The issue will come if the key doesn't exist. How can I check this in the .ForEach function? I'd like to use the ternary operator but it doesn't seem to work.

private Dictionary<string, Func<IniConfig, object>> typeMapping = new Dictionary<string, Func<IniConfig, object>>();

typeMapping["MB"] = ProcessMB;

public object ProcessMB(IniConfig file)
return null;

object iif(bool expression, object truePart, object falsePart)
{ return expression ? truePart : falsePart; }

FilesToProcess.ForEach(x => iif(typeMapping.ContainsKey(x.ExtractType), typeMapping[x.ExtractType](x), Error(x)));

This highlights the 2nd parameter in the iif() call with error: Argument 2: cannot convert from 'void' to 'object', and the same thing for the Error(x) part.

So it seems like the ternary operator returns an object? So if I change my Action to a Func and have the return type be object and make my functions return object it compiles, but when I run a test with an invalid key it doesn't go into my Error() function it throws "The given key was not present in the dictionary" exception. I would expect it to do the ternary operation and see that typeMapping doesn't have the key and so fail to the Error() function. What am I missing?

Answer Source

Your iif() method is counter-intuitive here, and it seems like an over-use of LINQ. Here is what I would do:

foreach (var file in filesToProcess)
    Func<IniConfig, object> action;
    if (typeMapping.TryGetValue(file.ExtractType, out action))

Makes your code easier to read too :)


I Have found a generic way to do what you want. First you need to create an extension method for IDictionary<TKey,TVal> that simply returns the default value if a key does not exist:

public static TVal GetValueOrDefault<TKey, TVal>(this IDictionary<TKey, TVal> self, TKey key)
    TVal ret;
    self.TryGetValue(key, out ret);
    return ret;

Then you can use the null coalescing (??) operator:

FilesToProcess.ForEach((typeMapping.GetValueOrDefault(x.ExtractType) ?? Error)(x));
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download