Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 循环以填充类属性?_C#_Class_Oop_Properties - Fatal编程技术网

C# 循环以填充类属性?

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

假设我有一个拥有一系列属性(名字、姓氏、地址、城市等)的类人

我正在从Excel文件(使用优秀的EPPlus库)中提取数据来填充这些属性,其中每个列都与Person属性相同,顺序相同

有没有一种方法可以遍历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
对应于
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);
    }
}