LINQ - Dynamically Invoke ToDictionary

Viewed 42

Is there a way in .Net to dynamically invoke ToDictionary(<lambda key>, <lambda val>) to reduce boilerplate of returning a Dictionary when running LINQ expressions.

C# Example:

Dictionary<string, object> d_filt;

Dictionary<string, object> d_in = new Dictionary<string, object>();
d_in.Add("k1", 4);
d_in.Add("k2", 3);
d_in.Add("k3", 2);
d_in.Add("k4", 1);

// Current Expression:
d_filt = d_in.Where(p => p.value > 2)
             .ToDictionary(p => p.Key, p => p.Value);

// Preferred Expression:
d_filt = linq2Dict(d_in.Where(p => p.value > 2));

Where linq2Dict(<LinqObj>) is a helper that will dynamically invoke the ToDictionary(..) method.

I have tried Reflection library but it appears that ToDictionary is not available through the standard Reflection library I'm familiar with.

Note: VB is even more verbose:

Dim d_filt = d_in.Where(Function(p) p.value > 2).ToDictionary(Function(p) p.Key, Function(p) p.Value)

Of course, the slickest solution would be to add a ToDict() Extension which took no arguments resulting in:

// Preferred Expression:
d_filt = d_in.Where(p => p.value > 2).ToDict()
3 Answers

No reflection is necessary, just plain ol' generic

public static class Convert
{
    public static Dictionary<T,U> ToDict<T,U>(this IEnumerable<KeyValuePair<T,U>> source) where T : notnull
    {
        return source.ToDictionary(s=>s.Key,s=>s.Value);
    }
}

The constraint for T is because Dictionary can't use null keys.

As a bonus it maintains the fluent syntax, so you can just use

d_filt = d_in.Where(p => p.value > 2).ToDict();

To build on @Martheen's answer, here is how to implement ToDict() extension in VB:

Imports System.Runtime.CompilerServices

Module Convert
    <Extension()>
    Function ToDict(Of T, U)(ByVal source As IEnumerable(Of KeyValuePair(Of T, U))) As Dictionary(Of T, U)
        Return source.ToDictionary(Function(s) s.Key, Function(s) s.Value)
    End Function
End Module

Here is an implementation of linq2Dict() in VB:

Public Shared Function linq2Dict(Of T, U)(ByVal source As IEnumerable(Of KeyValuePair(Of T, U))) As Dictionary(Of T, U)
    Return source.ToDictionary(Function(s) s.Key, Function(s) s.Value)
End Function

Eg:

d_filt = linq2Dict(d_in.Where(p => p.value > 2))
Related