【发布时间】:2020-02-18 15:30:21
【问题描述】:
我在制表符分隔值 (TSV) 文本文件中有数据,我想读取这些数据并(最终)存储在数据库表中。对于 TSV 文件,每行包含一条记录,但在一个文件中,记录可以有 2 个字段,在另一个文件中可以有 4 个字段,等等。我编写了工作代码来处理 2 字段记录,但我认为这可能是一个好的一个(或两个)通用方法的案例,而不是为每种记录编写新方法。但是,由于两个问题,我无法对此进行编码:我无法创建一个新对象来保存记录数据,并且我不知道如何使用反射来一般地填充我的对象的实例变量。
我查看了其他几个类似的帖子,包括Datatable to object by using reflection and linq
下面是有效的代码(如果重要的话,这是在 Windows 中)以及无效的代码。
public class TSVFile
{
public class TSVRec
{
public string item1;
public string item2;
}
private string fileName = "";
public TSVFile(string _fileName)
{
fileName = _fileName;
}
public TSVRec GetTSVRec(string Line)
{
TSVRec rec = new TSVRec();
try
{
string[] fields = Line.Split(new char[1] { '\t' });
rec.item1 = fields[0];
rec.item2 = fields[1];
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show("Bad import data on line: " +
Line + "\n" + ex.Message, "Error",
System.Windows.Forms.MessageBoxButtons.OK,
System.Windows.Forms.MessageBoxIcon.Error);
}
return rec;
}
public List<TSVRec> ImportTSVRec()
{
List<TSVRec> loadedData = new List<TSVRec>();
using (StreamReader sr = File.OpenText(fileName))
{
string Line = null;
while ((Line = sr.ReadLine()) != null)
{
loadedData.Add(GetTSVRec(Line));
}
}
return loadedData;
}
// *** Attempted generic methods ***
public T GetRec<T>(string Line)
{
T rec = new T(); // compile error!
Type t = typeof(T);
FieldInfo[] instanceVars = t.GetFields();
string[] fields = Line.Split(new char[1] { '\t' });
for (int i = 0; i < instanceVars.Length - 1; i++)
{
rec. ??? = fields[i]; // how do I finish this line???
}
return rec;
}
public List<T> Import<T>(Type t)
{
List<T> loadedData = new List<T>();
using (StreamReader sr = File.OpenText(fileName))
{
string Line = null;
while ((Line = sr.ReadLine()) != null)
{
loadedData.Add(GetRec<T>(Line));
}
}
return loadedData;
}
}
我看到了这条线 T rec = 新 T(); 在上述帖子中,但它对我不起作用......
如果可能的话,我将不胜感激有关如何完成这项工作的任何建议。我想了解更多关于将反射与泛型结合使用的信息,因此我不仅想了解如何使用,还想了解原因。
【问题讨论】:
-
编译错误是什么?我猜它说你需要通过添加
where T: class来约束T。因为 T 有可能是不可实例化的东西,所以你会得到一个编译错误。 -
" 但我认为这可能是一个(或两个)通用方法的好案例,而不是为每种记录编写新方法。”泛型当然假设了一些共同特征/行为,这是由一个泛型约束定义的,例如类似
where T: MyBaseClass。在我看来,不同类型的不同成员并不符合这一点。 -
我同意,作为 TSV,使用带有值字符串数组的泛型类更有意义,或者如果您有具体类型,并且您真的想要一种通用的方式来实例化它们(而不使用工厂模式),您可以简单地给他们一个
params string []构造函数并使用激活器 createinstance。 -
TSVRec 的值应该有一个
List<string>。添加方法以将它们转换为不同的类型。从本质上讲,如果您正在编写System.Data.DataRow,请弄清楚您需要什么,然后只需使用 DataRow 和 DataTable。这里没有问题,泛型非常适合解决,除了可能使用List<T>来收集编译时已知的某些字段或记录类型。当你的泛型类或方法变成一堆反射时,它就不是真正的泛型了。 -
泛型非常有用,但它们并不是解决大多数问题的正确方法。
标签: c# generics reflection instance-variables