循环填充 class 属性?
Loop to fill class properties?
假设我有一个 Class 人,他有很多属性(名字、姓氏、地址、城市等)
我正在从 Excel 文件(使用出色的 EPPlus 库)中提取数据以填充这些属性,其中每一列都与 Person 属性相同,顺序相同。
有没有办法遍历 Class Person 中的所有属性来填充它们?
目前我正在这样做:
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
这看起来有点不雅。我可以使用一些循环吗?
这里最大的障碍是如何将列索引自动关联到特定 属性。 IE。代码应该如何知道列索引 1
对应于 FirstName
属性.
可以从您的 class 类型中检索 PropertyInfo
对象的列表。这些对象可以与您的 class 实例一起使用来设置或获取 属性 值。因此,假设您有某种方法可以将列索引映射到特定的 属性,从而映射到特定的 PropertyInfo
对象,您可以按照这样的方式对 PropertyInfo
对象的列表进行排序使用与列相同的索引(或者更可能的是,列索引减一)。
但是反射速度很慢,而且坦率地说,它可能会令人困惑且难以使用,尤其是对于非专家而言。也很难让反射在速度方面表现良好。
就个人而言,我会坚持你已经拥有的东西。 IE。为适当的索引显式编写适当的赋值。我要做的一个修改是定义 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);
}
}
或者,您可以使用 Action<Person, string>
委托数组抽象赋值:
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);
}
}
恕我直言,以上任何一种方法都比反射更简单、更容易理解。即使您在工作表数据的列名称和您的实际 属性 名称之间具有精确的一对一对应关系,这也是正确的,如果没有,则更是如此。 :)
假设我有一个 Class 人,他有很多属性(名字、姓氏、地址、城市等)
我正在从 Excel 文件(使用出色的 EPPlus 库)中提取数据以填充这些属性,其中每一列都与 Person 属性相同,顺序相同。
有没有办法遍历 Class Person 中的所有属性来填充它们?
目前我正在这样做:
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
这看起来有点不雅。我可以使用一些循环吗?
这里最大的障碍是如何将列索引自动关联到特定 属性。 IE。代码应该如何知道列索引 1
对应于 FirstName
属性.
可以从您的 class 类型中检索 PropertyInfo
对象的列表。这些对象可以与您的 class 实例一起使用来设置或获取 属性 值。因此,假设您有某种方法可以将列索引映射到特定的 属性,从而映射到特定的 PropertyInfo
对象,您可以按照这样的方式对 PropertyInfo
对象的列表进行排序使用与列相同的索引(或者更可能的是,列索引减一)。
但是反射速度很慢,而且坦率地说,它可能会令人困惑且难以使用,尤其是对于非专家而言。也很难让反射在速度方面表现良好。
就个人而言,我会坚持你已经拥有的东西。 IE。为适当的索引显式编写适当的赋值。我要做的一个修改是定义 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);
}
}
或者,您可以使用 Action<Person, string>
委托数组抽象赋值:
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);
}
}
恕我直言,以上任何一种方法都比反射更简单、更容易理解。即使您在工作表数据的列名称和您的实际 属性 名称之间具有精确的一对一对应关系,这也是正确的,如果没有,则更是如此。 :)