假设我从服务(我无法控制)获取数据:
public class Data
{
// an array of column names
public string[] ColumnNames { get; set; }
// an array of rows that contain arrays of strings as column values
public string[][] Rows { get; get; }
}
在中间层,我想将其映射/翻译到可以将其中IEnumerable<Entity>
的列名表示为我的类中的属性的位置。我说可能是因为我可能不需要服务返回的所有数据,而只需要其中的一部分。Data
Entity
转型
这是进行翻译的算法的抽象:
- 创建一个
IDictionary<string, int>
,ColumnNames
以便我可以轻松地将各个列名映射到各个行中的数组索引。 - 使用反射来检查我的
Entity
属性名称,以便我能够将它们与列名匹配 - 根据 #1 中完成的映射遍历
Data.Rows
并创建我的对象并填充属性。Entity
可能使用反射和SetValue
属性来设置它们。
优化
上层算法当然可以工作,但我认为因为它使用反射,它应该做一些缓存,可能还有一些即时编译,这可以大大加快速度。
完成第 1 步和第 2 步后,我们实际上可以生成一个方法,该方法采用字符串数组并直接使用索引实例化我的实体,然后对其进行编译和缓存以供将来重用。
我通常会得到一页结果,因此后续请求将重用相同的编译方法。
附加事实
这不是问题(和答案)的必要条件,但我还创建了两个属性,当它们的名称不匹配时,它们有助于列到属性的映射。我创建了最明显的MapNameAttribute
(它需要一个字符串,并且还可以选择启用区分大小写)和我的不应该映射到任何数据IgnoreMappingAttribute
的属性。Entity
但是这些属性是在上层算法的第 2 步中读取的,因此会根据此声明性元数据收集和重命名属性名称,以便它们与列名称匹配。
问题
生成和编译这种方法的最佳和最简单的方法是什么?Lambda 表达式?CSharpCodeProvider
班级?
你可能有一个生成和编译代码的例子吗?我猜映射是一个相当常见的场景。
注意:与此同时,我将研究 PetaPoco(也许还有 Massive),因为 afaik 他们都在运行中进行编译和缓存,完全是为了映射目的。