返回泛型列表

本文关键字:列表 泛型 返回 | 更新日期: 2023-09-27 18:31:54

我正在尝试在从文件加载值后返回通用列表。 但是,在对类型操作进行了大量摆弄之后,我仍然无法让它同意我的观点。 代码如下;我的问题是:

  1. 我是否需要像下面开始的那样识别每种密钥类型,或者有更快的方法? 我看到"哪里 T:..."可能在这里相关,但如果可能的话,我想允许日期时间、整数、字符串、双精度等,我看不出如何使用"哪里"来做这些。
  2. 为什么我无法将我的日期时间项目添加到日期时间列表中?
  3. 当我尝试获取类型(列表类型)时,这似乎超出了范围。 即使我在上面使用它的行中声明类型,它也说不存在这样的对象。

非常感谢您的想法

public static List<T> FileToGenericList<T>(string FilePath, int ignoreFirstXLines = 0, bool stripQuotes = true)
{
    List<T> output = new List<T>();
    Type listType = output.GetType().GetGenericArguments()[0];
    try
    {
        using (StreamReader stream = new StreamReader(File.Open(FilePath, FileMode.Open)))
        {
            string line;
            int currentLine = 0;
            while ((line = stream.ReadLine()) != null)
            {
                // Skip first x lines
                if (currentLine < ignoreFirstXLines) continue;
                // Remove quotes if needed
                if (stripQuotes == true)
                {
                    line = line.Replace(@"""", @"");
                }
                // Q1 - DO I HAVE TO HAVE THIS FOR EACH TYPE OR IS THERE A QUICKER WAY
                if (listType == typeof(System.DateTime))
                {
                    DateTime val = new System.DateTime();
                    val = DateTime.Parse(line);
                    // Q2 ERROR: 'Argument type is not assignable to parameter type 'T''                    
                    output.Add(val);
                    // For some reason the type 'listType' from above is now out of scope when I try a cast
                    output.Add((listType)val);
                }
                if (listType == typeof(System.String))
                {
                    //DateTime val = new System.DateTime();
                    //val = DateTime.Parse(line);
                    //output.Add(val.ToString());
                }
                // Continue tracking for line skipping purposes
                currentLine++;
            }
        }
    }
    catch (Exception ex)
    {
        throw new Exception("Error - there was a problem reading the file at " + FilePath + ".  Error details: " + ex.Message);
    }    
    return output;
}

返回泛型列表

我认为与其将解析逻辑编码到FileToGenericList方法中,不如将其重构并将其作为 lambda 传递。 下面是演示此方法的快速控制台应用:

class Program
{
    static void Main(string[] args)
    {
        // second argument is a lambda that describes how to convert the line into the type you require
        var dateList = FileToGenericList<DateTime>("dates.txt", DateTime.Parse);
        var stringList = FileToGenericList<string>("strings.txt", s => s);
        var intList = FileToGenericList<int>("integers.txt", Int32.Parse); 
        Console.ReadLine();
    }
    static List<T> FileToGenericList<T>(string filePath, Func<string, T> parseFunc, int ignoreFirstXLines = 0, bool stripQuotes = true)
    {
        var output = new List<T>();
        try
        {
            using (StreamReader stream = new StreamReader(File.Open(filePath, FileMode.Open)))
            {
                string line;
                int currentLine = 0;
                while ((line = stream.ReadLine()) != null)
                {
                    // Skip first x lines
                    if (currentLine < ignoreFirstXLines)
                        continue;
                    // Remove quotes if needed
                    if (stripQuotes == true)
                        line = line.Replace(@"""", @"");
                    var parsedValue = parseFunc(line);
                    output.Add(parsedValue);
                    currentLine++;
                }
            }
        }
        catch (Exception ex)
        {
            throw new Exception("Error - there was a problem reading the file at " + FilePath + ".  Error details: " + ex.Message);
        }    
        return output;
   }
}

//Q1 - 我是否必须为每种类型提供这个,或者是否有更快的方法

以下是一些帮助您入门的测试代码:

using System;
using System.Collections.Generic;
namespace AddGenericToList
{
    class Program
    {
        static void Main(string[] args)
        {
            var tc = new ListClass<string>();
            tc.Add("a value");
            tc.Add(123);
            tc.Add(DateTime.Now);
        }
    }
    internal class ListClass<T>
    {
        private readonly List<T> list = new List<T>();
        public void Add(object value)
        {
            list.Add((T)Convert.ChangeType(value, Nullable.GetUnderlyingType(typeof (T)) ?? typeof (T)));
        }
    }
}

但是,无效的强制转换将引发错误。 例如,DateTime可以转换为string但不能转换为int

对于您的问题#3:您收到"超出范围"错误的原因是您无法转换为变量。output.Add((listType)val);不是合法的 C# 语句 - 只能强制转换为显式类型定义。幸运的是,您不需要通过 Type listType 变量进行所有转换,因为您有一个显式类型定义 - 您作为泛型参数获得的 T。你可以在帕瓦尔的答案深处看到@Pravin答案:output.Add(val as T);,或者最好使用显式强制转换语法output.Add((T)val),因为T不一定是引用类型。

编辑:

你是对的,(T)val不会编译,因为编译器不会为我们加倍努力并决定 T 是 DateTime,尽管我们之前进行了检查。所以你可以这样做:

 (T)Convert.ChangeType(val, typeof(T)));

这会将您的 DateTime val 转换为 T(也是 DateTime),这足以满足编译器的要求。