返回通用列表

时间:2012-04-23 05:16:46

标签: c# generics collections generic-method

我正在尝试从文件加载值后返回通用列表。然而,经过多次摆弄类型操作后,我仍然不能同意我的观点。代码如下;我的问题是:

  1. 我是否需要确定每个关键类型,例如我从下面开始,或者是否有更快的方法?我看到'哪里T:......'在这里可能是相关的,但我想允许DateTime,int,string,double等,如果可能的话,我看不到如何用'where'来做那些。
  2. 为什么我不能将DateTime项添加到datetime的列表中?
  3. 当我尝试获取类型(listType)时,这似乎超出了范围。即使我在上面的行中声明了我使用它的类型,它也表示不存在这样的对象。
  4. 非常感谢您的想法

    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;
    }
    

3 个答案:

答案 0 :(得分: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;
   }
}

答案 1 :(得分:2)

// 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

答案 2 :(得分:0)

对于你的问题#3:你得到“超出范围”错误的原因是你不能转换为变量。您的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 val转换为T(也是DateTime),这足以满足编译器的需要。