Tuesday, November 5, 2013

Tricky LINQ ToDictionary Where Action is the Value

This is going to be a quick one, but something I wanted to jot down before I forgot it. I needed a Dictionary<MyEnum, Action> and figured I would use LINQ's awesome ToDictionary<,>() method. I've used this plenty of times before and so I figured this would be a snap:

    private readonly Dictionary<MyEnum, Action> _actions;

    public Keyboard()
    {
        _actions = Enum.GetValues(typeof(MyEnum))
                       .Cast<MyEnum>()
                       .ToDictionary(x => x, x => () => { });
    }

Feeling good about my awesome LINQ statement, I went to move on when I noticed that my precious had red squigglies under it. Ah, probably just a typo or something. I mean, I am susceptible to those sometimes, I suppose. Upon further inspection, it was not a typo but a fun little error:

Cannot convert lambda expression to type 'System.Collections.Generic.IEqualityComparer<Foo.Bar.MyEnum>' because it is not a delegate type

Even more fun, this method was insisting I was trying to create a Dictionary<MyEnum, MyEnum>. No I'm not! What the heck!

Just Breathe...

Ah yes, it is easy to forget that there are four overloads for ToDictionary. Three of which are ToDictionary<TSource, TKey>, all of which an Action perfectly conflicts, and fourth which is ToDictionary<TSource, TKey, TElement>. So, my implementation, above, caused the compiler to become confused since it thought I was trying to pull off passing in an Action as an IEqualityComparer. So, we need to force the compiler to pick the last overload by specifying all the Ts:

        _actions = Enum.GetValues(typeof(MyEnum))
                       .Cast<MyEnum>()
                       .ToDictionary<MyEnum, MyEnum, Action>(x => x, x => () => { });

Simple really.