泛型基本用法

cil*_*ler 6 c# generics

我继续在我的课程中使用下面的函数,并希望将其写为泛型.

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

我抓了下面的代码,但没有用

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

请指教.谢谢!

cdh*_*wie 11

您不能new以这种方式使用泛型类型创建实例1.考虑为该函数提供工厂委托:

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(',')));
}
Run Code Online (Sandbox Code Playgroud)

然后你会这样称呼它:

var myObjects = Get("file.csv", row => new MyObject(row));
Run Code Online (Sandbox Code Playgroud)

或者,您可以返回IEnumerable<string[]>2并让调用者决定如何处理它:

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

然后调用者可以这样做:

var myObjects = Get("file.csv").Select(row => new MyObject(row));
Run Code Online (Sandbox Code Playgroud)

1您可以提供where T : new()约束,然后您可以使用泛型类型创建新实例,但仅当它提供无参数构造函数时; 在构造泛型类型时,您无法提供参数,并且您的用例似乎需要它.工厂代表是您最好的选择.

作为参考,这是使用泛型类型的构造在无参数情况下的外观:

public static T Create<T>() where T : new()
{
    return new T();
}
Run Code Online (Sandbox Code Playgroud)

2更好的是IEnumerable<IEnumerable<string>>假设你的MyObject构造函数也接受IEnumerable<string>了.

  • @Default确实有.实际上,`new T()`被编译为`Activator.CreateInstance <T>()`.但是,应该注意这种技术(使用CreateInstance将参数传递给构造函数)每次都会使用反射,从而导致潜在的严重性能损失.使用工厂委托不仅可以提供更大的灵活性(也许您只想构建一个对象),同时还可以利用已编译的代码并避免反射成本. (2认同)