Generics and Functions in C#
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>, IEnum开发者_如何学编程erable<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.
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);
}
}
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).
From the usage I would say you need a functuion that returns an IEnumerable<>
, not a Func<>
.
Which would simplify the whole thing to:
IEnumerable<T> parser<T>(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
{
// empty catch alert
}
}
return items;
}
And your usecase is missing a semicolon (after ToInt32()
) :
string csvList ="1,2,3";
IEnumerable<int> list =
parser<int>(csvList, (val) => { return Convert.ToInt32(val); });
Edit, thanks to BFree: if you don't need the exceptionhandling to be inside parser (and I hope that empty catch is there only in the sample code), you can eliminate the List<T> items
and use yield return
instead.
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));
精彩评论