cilerler
cilerler

Reputation: 9450

Generics basic usage

I keep using the function below in my classes and would like to write it as generics.

public static IEnumerable<MyObject> Get(string csvFile)
{
    return csvFile
        .ReadAsStream()
        .SplitCrLf()
        .Where(row => !string.IsNullOrWhiteSpace(row))
        .Select(row => new MyObject(row.Split(',')));
}

I scratch the code below but didn't work

public static IEnumerable<T> Get<T>(string csvFile)
{
    return csvFile
        .ReadAsStream()
        .SplitCrLf()
        .Where(row => !string.IsNullOrWhiteSpace(row))
        .Select(row => new typeof(T)(row.Split(',')));
}

Please advise. Thank you!

Upvotes: 6

Views: 161

Answers (1)

cdhowie
cdhowie

Reputation: 169413

You cannot use new to create instances using generic types in this way1. Consider supplying a factory delegate to the function:

public static IEnumerable<T> Get<T>(string csvFile, Func<string[], T> factory)
{
    return csvFile
        .ReadAsStream()
        .SplitCrLf()
        .Where(row => !string.IsNullOrWhiteSpace(row))
        .Select(row => factory(row.Split(',')));
}

Then you would call it like so:

var myObjects = Get("file.csv", row => new MyObject(row));

Alternatively, you can return an IEnumerable<string[]>2 and let the caller decide what to do with it:

public static IEnumerable<string[]> Get(string csvFile)
{
    return csvFile
        .ReadAsStream()
        .SplitCrLf()
        .Where(row => !string.IsNullOrWhiteSpace(row))
        .Select(row => row.Split(','));
}

Then the caller could do:

var myObjects = Get("file.csv").Select(row => new MyObject(row));

1You can supply the where T : new() constraint and then you can create new instances using a generic type, but only when it provides a no-argument constructor; you cannot provide arguments when constructing generic types, and your use case appears to require it. A factory delegate is your best option here.

For reference, this is how construction using generic types would look in the no-argument case:

public static T Create<T>() where T : new()
{
    return new T();
}

2Even better would be an IEnumerable<IEnumerable<string>> assuming that your MyObject constructor accepts IEnumerable<string> as well.

Upvotes: 11

Related Questions