C# 循环以填充类属性?
假设我有一个拥有一系列属性(名字、姓氏、地址、城市等)的类人 我正在从Excel文件(使用优秀的EPPlus库)中提取数据来填充这些属性,其中每个列都与Person属性相同,顺序相同 有没有一种方法可以遍历Person类中的所有属性来填充它们 目前我正在这样做:C# 循环以填充类属性?,c#,class,oop,properties,C#,Class,Oop,Properties,假设我有一个拥有一系列属性(名字、姓氏、地址、城市等)的类人 我正在从Excel文件(使用优秀的EPPlus库)中提取数据来填充这些属性,其中每个列都与Person属性相同,顺序相同 有没有一种方法可以遍历Person类中的所有属性来填充它们 目前我正在这样做: person.FirstName= worksheet.Cells[2, 1].Text; person.LastName= worksheet.Cells[2, 2].Text; person.Address= worksheet.C
person.FirstName= worksheet.Cells[2, 1].Text;
person.LastName= worksheet.Cells[2, 2].Text;
person.Address= worksheet.Cells[2, 3].Text;
person.City= worksheet.Cells[2, 4].Text;
person.Age= worksheet.Cells[2, 5].Text;
//repeat for a dozen more properties
这似乎有点不雅。有什么循环可以使用吗?这里最大的障碍是如何自动将列索引与特定属性关联。即,代码如何知道列索引
1
对应于FirstName
属性
可以从类的类型中检索PropertyInfo
对象的列表。这些对象可以与类的实例一起使用,以设置或获取属性值。因此,假设您有某种方法将列索引映射到特定属性,从而映射到特定的PropertyInfo
对象,您可以对PropertyInfo
对象列表进行排序,以便使用与列相同的索引(或者更可能的是,列索引减去一)
但反思是缓慢的,坦率地说,可能会令人困惑和难以使用,特别是对于非专家。在速度方面,也很难让反射很好地执行
就我个人而言,我会坚持你已经拥有的。即,明确地为适当的索引编写适当的赋值。我要做的一个修改是,不要在代码中使用文本,而是定义const
值。例如:
const int firstNameColumn = 1;
const int lastNameColumn = 2;
// etc.
void InitializeFromCell(Worksheet worksheet, int rowIndex)
{
person.FirstName = worksheet.Cells[rowIndex, firstNameColumn].Text;
person.LastName = worksheet.Cells[rowIndex, lastNameColumn].Text;
// etc.
}
您可以考虑用单独的方法从列到属性抽象映射,以便至少只需编写一次代码:
void SetIndexedProperty(Person person, int propertyIndex, string value)
{
switch (propertyIndex)
{
case firstNameColumn:
person.FirstName = value;
break;
case lastNameColumn:
person.LastName = value;
break;
// etc.
}
}
void InitializeFromCell(Worksheet worksheet, int rowIndex)
{
for (int columnIndex = 1; columnIndex <= numberOfColumns; columnIndex++)
{
SetIndexedProperty(person, columnIndex, worksheet.Cells[rowIndex, columnIndex].Text);
}
}
void SetIndexedProperty(Person-Person,int-propertyIndex,字符串值)
{
开关(属性索引)
{
案例名称列:
person.FirstName=值;
打破
案例lastNameColumn:
person.LastName=值;
打破
//等等。
}
}
void InitializeFromCell(工作表工作表,整数行索引)
{
对于(int columnIndex=1;columnIndex person.FirstName=value,
(person,value)=>person.LastName=value,
//等等。
}
void InitializeFromCell(工作表工作表,整数行索引)
{
对于(int columnIndex=1;columnIndex)单元格集合是否包含映射回属性的值?就像Cells[1,1]
equal“FirstName”?如果是,则可以使用反射迭代集合并将其映射回objectCells上的属性[1,X]是列名(在EEPlus库中,它实际上看起来像单元格[y,x])。它们在水平方向上的顺序与我的类属性在垂直方向上的顺序相同。我的属性名称与列名不完全匹配(命名约定等)。我对反射没有任何经验。你能给我指出正确的方向吗?在MSDN和这里的堆栈溢出上,有许多关于如何使用反射的示例。请参见Type.GetProperties()
method。但请注意,特别是在输入数据和类属性名称之间没有精确对应的情况下,这可能不容易实现。如果您尝试使用反射但遇到问题,请提出一个问题,准确显示您实际尝试了什么,并对您正在进行的操作进行清晰、具体的解释麻烦。对于你来说,将17个属性硬编码为一个特定的列号会更快,而且你将保持类型安全性,你会在反射中丢失。唯一的原因是,如果在源文件中的列号和顺序可以改变,因为你的列名和属性名不匹配,所以您必须创建一个应用于每个属性的属性,以处理属性名称到列名的映射,然后编写反射代码。反射解决方案将远不如您当前所做的“优雅”。您还需要花费大量的时间(相对)性能方面的成功。正如@DStanley所提到的,当您完成所有这些工作时,您已经完成了编写属性的手动映射和对其他内容进行非编码的工作。感谢您提供的详细提示。我非常喜欢使用常量值提高代码可读性的想法
static readonly Action<Person, string>[] _propertyIndexers =
{
(person, value) => person.FirstName = value,
(person, value) => person.LastName = value,
// etc.
}
void InitializeFromCell(Worksheet worksheet, int rowIndex)
{
for (int columnIndex = 1; columnIndex <= numberOfColumns; columnIndex++)
{
_propertyIndexers[columnIndex - 1](person, worksheet.Cells[rowIndex, columnIndex].Text);
}
}