循环以填充类属性?

时间:2015-07-01 16:47:19

标签: c# class oop properties

假设我有一个具有一堆属性的类人(FirstName,LastName,Address,City等)

我正在提取数据以从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

这似乎相当不优雅。我可以使用一些循环吗?

1 个答案:

答案 0 :(得分:1)

这里最大的障碍是如何自动将列索引与特定属性相关联的问题。即代码应该如何知道列索引1对应于FirstName属性。

可以从类的类型中检索PropertyInfo个对象的列表。这些对象可以与类的实例一起使用来设置或获取属性值。因此,假设您有一些方法可以将列索引映射到特定属性,从而映射到特定的PropertyInfo对象,您可以使用相同的索引来排序PropertyInfo对象列表至于列(或更可能的是,列索引减1)。

但反思很慢,坦率地说,可能会让人感到困惑和难以使用,特别是对非专家而言。在速度方面也很难让反思表现得很好。

就个人而言,我会坚持你已经拥有的东西。即显式地为适当的索引编写适当的赋值。我做的一个修改是代替在代码中使用文字,定义const值。 E.g:

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);
    }
}

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