返回一个通用列表

3
我想从文件中加载值后返回一个通用列表,但是在进行类型操作后,我仍然无法使它与我一致。下面是代码;我的问题是:
  1. 我需要像我下面开始的那样识别每个键类型吗,还是有更快的方法?我看到“where T:...”可能与此相关,但如果可能的话,我想允许DateTime、int、string、double等类型,并且我不知道如何使用'where'来做到这些。
  2. 为什么我不能将DateTime项添加到datetime列表中?
  3. 当我尝试获取类型(listType)时,它似乎超出了范围。即使我在使用它的上一行中声明了类型,它也会说不存在这样的对象。
感谢您的想法。
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;
}

另外,检查一下如何在文件中迭代行,如果你想跳过其中的任何一行... - JleruOHeP
1
你的忽略前X行代码无法正常工作,因为在迭代到下一行之前需要增加当前行数。 - 000
在第二行中,你可以写成 Type listType = typeof(T),实际上如果我在写这个代码的话,我会在所有地方都使用 typeof(T) 而不是 listType 变量。 - 000
3个回答

3

我认为将解析逻辑编码到您的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;
   }
}

真是太棒了 - 我也会把它加入我的工具包! :) - Glinkot

2

//问题1 - 我需要为每种类型都有这个吗?还是有更快的方法?

下面是一些测试代码,可以帮助您入门:

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


嗨,Eben,太棒了!我已经测试过它,使用 DateTime、int、double 和 string,所有都能正常工作。如果我们将浮点数放入输入并定义为整数,则会出现错误,这一点我同意。不过,这非常好。我甚至考虑如何将其适应于将多字段文件读入元组 - 这也很方便!谢谢,Eben。 - Glinkot

0
对于您的第三个问题:您收到“超出范围”错误的原因是您无法将其转换为变量。您的output.Add((listType)val); 不是合法的 C# 语句——您只能强制转换为显式类型定义。幸运的是,您不需要通过Type listType 变量进行所有转换,因为您作为泛型参数获得的 T 已经有一个明确的类型定义。 您可以在 @Pravin Pawar 的答案中看到答案:output.Add(val as T); 或者更好的做法是使用显式的转换语法output.Add((T)val),因为T不一定是引用类型。

编辑:

您是正确的,(T)val不能通过编译,因为编译器没有为我们多加努力,决定 T 是 DateTime,尽管我们之前检查了。所以您可以这样做:

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

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


嗨。我尝试了output.Add(T)val,但无法编译。不过还是谢谢你的留言! - Glinkot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接