views:

208

answers:

3

Here is some code, it won't compile but essentially want I want to create is a function that parses as CSV file and then converts the values in the CSV list to a specific type.

    Func<string, Func<string,T>, IEnumerable<T>> parser =(string csv, Func<string, T> newFunc) =>
    {
        List<T> items = new List<T>();
        string[] ary = csv.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
        foreach (string val in ary)
        {
            try
            {
                items.Add(newFunc(val));
            }
            catch { }
        }
        return items;
    }

I want this function to be generic so T is the type that I want the CSV list to be converted to. The usage of this function would be something like:

 string csvList ="1,2,3";
        IEnumerable<int> list = parser(csvList, (string val) => { return Convert.ToInt32(val)});

However this obviously won't work because I haven't defined T. So is it possible to define T in a similar manner to generic methods like so:

    Func<T><string, Func<string,T>, IEnumerable<T>> parser =(string csv, Func<string, T> newFunc) =>
    {
        List<T> items = new List<T>();
        string[] ary = csv.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
        foreach (string val in ary)
        {
            try
            {
                items.Add(newFunc(val));
            }
            catch { }
        }
        return items;
    }

And then use this like so:

string csvList ="1,2,3";
        IEnumerable<int> list = parser<int>(csvList, (string val) => { return Convert.ToInt32(val)});

Is there a way of doing something like this in C#?

-- Further Edit

Thanks to those of you have respond, in the code I have written I actually use a method like you have described, but I was wondering just a general aside if it was possible to do this as Func without the need for a method call.

+2  A: 

Your function signature for parser is syntactically incorrect and should be defined as follows.

Func<string, Func<string,T>, IEnumerable<T>>
    parser<T>(string csv, Func<string, T> newFunc)
{
    // implementation
}

Note, that when defining a generic function, you need to specify the generic parameters after the function name, and before the parameter list (see parser<T> above).

Steve Guidi
+2  A: 

Maybe I'm missing something but I think this is what you need:

public IEnumerable<T> Parse<T>(string csv, Func<string, T> func)
{
   foreach(var item in csv.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries))
   {
      yield return func(item);
   }
}
BFree
Yes, the `items` can be removed as well, I missed that. I'll borrow it though.
Henk Holterman
A: 

Try this out. I think this accomplishes what you're trying to do without a lot of hocus pocus.

string csvList = "1,2,3";
IEnumerable<int> list = parser<int>(csvList, Convert.ToInt32);



static IEnumerable<T> parser<T>(string csv, Converter<string, T> converter)
{
    string[] array = csv.Split(new string[] { "," }, 
                        StringSplitOptions.RemoveEmptyEntries);

    T[] items = Array.ConvertAll(array, converter);

    return items;
}

Update: If you want a single line, you could do it this way:

string csvList = "1,2,3";
var list = csvList.Split(new string[] { "," }, 
           StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x));
Scott P
I actually use a method in my code but I wanted to know if it was possible without and using a Func instead.
Michael Edwards
Take a look at my edit. Is this what you were looking for?
Scott P