Search code examples
c#.netgenericscode-reuse

Convert a generic IEnumerable<T> to IEnumerable<KeyValuePair> (C#)


In the following code, I need to explicitly mention CountryId and CountryName but I would like to avoid that and trying to create a generic method.

public struct KeyValueStruct
{
    public int Key { get; set; }
    public string Value { get; set; }
}

private static IEnumerable<KeyValueStruct> ConvertPocoToKeyValueList(IEnumerable<CountryPoco> list)
{
    var result = new List<KeyValueStruct>();

    if (list != null)
    {
        foreach (var item in list)
        {
            result.Add(new KeyValueStruct()
            {
                Key = item.CountryId,
                Value = item.CountryName
            });
        }
    }

    return result;
}

I know from the list that first property is always integer (which is CountryId in this example) and second property would be String.

I was thinking to implement using Generics but am not sure is this the best approach, see my proposed code (it's not working though).

private static IEnumerable<KeyValueStruct> ConvertPocoToKeyValueList<T>(T list) 
{
    var result = new List<KeyValueStruct>();

    if (list != null)
    {
        foreach (var item in list)
        {
            result.Add(new KeyValueStruct()
            {
                Key = item.CountryId,
                Value = item.CountryName
            });
        }
    }

    return result;
}

If you have a better idea to achieve the same result, then please propose.


Solution

  • You can make that generic by passing the properties to be used as Key and value. I think using the generic struct named KeyValuePair<Tkey, TValue> is better than reinventing the wheel yourself:

    private static IEnumerable<KeyValuePair<Tkey, TValue>> 
                           ConvertPocoToKeyValueList<TSource, Tkey, TValue>
                                        (IEnumerable<TSource> list,
                                         Func<TSource, Tkey> keySelector,
                                         Func<TSource, TValue> valueSelector)
            {
                return list.Select(item => new KeyValuePair<Tkey, TValue>
                                              (keySelector(item), valueSelector(item)));
            }
    

    Usage:

    var result = ConvertPocoToKeyValueList(list, x=> x.CountryId, x=> x.CountryName);
    

    You can even do that without using this generic method by using directly:

    var result = list.Select(item => new KeyValuePair<Tkey, TValue>
                                                  (item.CountryId, item.CountryName));