views:

111

answers:

4

I have the following extension method that takes a List and converts it to a comma separated string:

    static public string ToCsv(this List<string> lst)
    {
        const string SEPARATOR = ", ";
        string csv = string.Empty;

        foreach (var item in lst)
            csv += item + SEPARATOR;

        // remove the trailing separator
        if (csv.Length > 0)
            csv = csv.Remove(csv.Length - SEPARATOR.Length);

        return csv;
    }

I want to do something analogous but apply it to a List (instead of List of String) , however, the compiler can't resolve for T:

    static public string ToCsv(this List<T> lst)
    {
        const string SEPARATOR = ", ";
        string csv = string.Empty;

        foreach (var item in lst)
            csv += item.ToString() + SEPARATOR;

        // remove the trailing separator
        if (csv.Length > 0)
            csv = csv.Remove(csv.Length - SEPARATOR.Length);

        return csv;
    }

What am I missing?

+7  A: 

Try changing the declaration to

static public string ToCsv<T>(this List<T> lst){ ...
Kevin Montrose
+3  A: 

Your function needs a generic parameter:

static public string ToCsv<T>(this List<T> lst)
                          ^^^
itowlson
+8  A: 

First, the method declaration should be:

public static string ToCsv<T>(this List<T> list) { // }

Note that the method must be parameterized; this is the <T> after the name of the method.

Second, don't reinvent the wheel. Just use String.Join:

public static string ToCsv<T>(this IEnumerable<T> source, string separator) {
    return String.Join(separator, source.Select(x => x.ToString()).ToArray());
}

public static string ToCsv<T>(this IEnumerable<T> source) {
    return source.ToCsv(", ");
}

Note that I've gone hog wild and generalized the method further by accepting an IEnumerable<T> instead of a List<T>.

In .NET 4.0 you will be able to say:

public static string ToCsv<T>(this IEnumerable<T> source, string separator) {
    return String.Join(separator, source.Select(x => x.ToString());
}

public static string ToCsv<T>(this IEnumerable<T> source) {
    return source.ToCsv(", ");
}

That is, we do not require to convert the result of source.Select(x => x.ToString()) to an array.

Finally, for an interesting blog post on this topic, see Eric Lippert's post Comma Quibbling.

Jason
my goodness, some of the solutions in the comments are baroque.
Jimmy
"baroque" or "broke"?
Muad'Dib
+2  A: 

You could make this more generic and use IEnumerable instead of a List< T >, after all you are not using any list-specific methods

public static string ToCsv<T>(this IEnumerable lst);
Muad'Dib