循环填充 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);
    }
}

恕我直言,以上任何一种方法都比反射更简单、更容易理解。即使您在工作表数据的列名称和您的实际 属性 名称之间具有精确的一对一对应关系,这也是正确的,如果没有,则更是如此。 :)