我有以下代码能够将 Reader
映射到简单对象。问题是万一对象是复合的,它就无法映射。如果它本身是一个类,我无法通过检查属性来执行递归
prop.PropertyType.IsClass
因为调用 DataReaderMapper()
需要 Type。关于如何实现或其他方法的任何想法?另外,目前我不希望使用任何 ORM。
public static class MapperHelper
{
/// <summary>
/// extension Method for Reader :Maps reader to type defined
/// </summary>
/// <typeparam name="T">Generic type:Model Class Type</typeparam>
/// <param name="dataReader">this :current Reader</param>
/// <returns>List of Objects</returns>
public static IEnumerable<T> DataReaderMapper<T>(this IDataReader dataReader)where T : class, new()
{
T obj = default(T);
//optimized taken out of both foreach and while loop
PropertyInfo[] PropertyInfo;
var temp = typeof(T);
PropertyInfo = temp.GetProperties();
while (dataReader.Read())
{
obj = new T();
foreach (PropertyInfo prop in PropertyInfo)
{
if (DataConverterHelper.ColumnExists(dataReader,prop.Name) && !dataReader.IsDBNull(prop.Name))
{
prop.SetValue(obj, dataReader[prop.Name], null);
}
}
yield return obj;
}
}
}
最佳答案
不要制作 DataReaderMapper
递归的。只需使映射部分递归即可:
static void Assign(IDataReader reader, object instance) {
foreach (PropertyInfo prop in PropertyInfo)
{
if (IsValue(prop))
{
prop.SetValue(obj, dataReader[prop.Name], null);
}
else if (IsClass(prop)) {
var subInstance = Activator.CreateInstance(prop.PropertyType);
prop.SetValue(obj, subInstance, null);
Assign(subInstance, dataReader);
}
}
}
就像那样。这会使用默认构造的实例递归地初始化所有类类型属性,并为它们分配数据读取器值。
代码明显简化了。我删掉了你的一些东西和IsValue
/IsClass
留给你喜欢的实现。此外,您可能希望使用命名方案,以便 a.b.c
作为列名映射到该属性。这可以通过将当前名称前缀作为参数传递给 Assign
来实现。 .
进一步注意,DataReaderMapper
不需要通用。我这么说是因为你为此苦苦挣扎。替换 typeof(T)
用Type
参数并返回 IEnumerable<object>
.然后调用Cast<T>()
根据你的方法的结果。所以你看到这个算法原则上可以在没有泛型的情况下工作。
关于c# - 通用关系到复合 C# 对象映射器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30230595/