我正在尝试从文件加载值后返回通用列表。然而,经过多次摆弄类型操作后,我仍然不能同意我的观点。代码如下;我的问题是:
非常感谢您的想法
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;
}
答案 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),这足以满足编译器的需要。