如何在C#中动态更改对象属性的数据类型?
动态将DataTable数据映射到C#对象并处理类型转换
核心思路梳理
你现在的做法是遍历DataTable的行与列,通过m2方法来衔接列名、目标对象和单元格值,核心需求应该是动态适配不同数据类型的转换与赋值——毕竟DataTable单元格值是object类型,而C#对象的属性有明确类型约束,得自动完成类型匹配转换。
实现m2方法的关键方案
我给你整理几个实用的实现方向,你可以根据场景选择:
1. 基础反射实现类型转换赋值
这是最直接的方式,通过反射拿到目标对象的对应属性,再把DataTable的单元格值转换成属性所需类型:
private void m2(string columnName, object targetObj, object cellValue) { // 获取目标对象的类型信息 Type targetType = targetObj.GetType(); // 根据列名(假设列名和属性名一致)获取对应属性 PropertyInfo prop = targetType.GetProperty(columnName); if (prop == null) { // 处理列名与属性名不匹配的情况,比如记录日志 Console.WriteLine($"目标对象中不存在名为 {columnName} 的属性"); return; } // 处理DataTable中DBNull的情况,转为对应类型的默认值 object valueToAssign = cellValue == DBNull.Value ? GetDefaultValue(prop.PropertyType) : cellValue; // 执行类型转换并赋值 try { object convertedValue = Convert.ChangeType(valueToAssign, prop.PropertyType); prop.SetValue(targetObj, convertedValue); } catch (Exception ex) { // 捕获类型转换异常,便于排查问题 Console.WriteLine($"列 {columnName} 的值转换失败:{ex.Message}"); } } // 辅助方法:获取指定类型的默认值 private object GetDefaultValue(Type type) { return type.IsValueType ? Activator.CreateInstance(type) : null; }
2. 缓存属性信息提升性能
如果你的DataTable数据量很大,反复反射会带来性能开销,建议提前缓存目标对象的属性映射:
// 静态字典缓存属性信息,避免重复反射 private static readonly Dictionary<Type, Dictionary<string, PropertyInfo>> _propertyCache = new(); private void m2(string columnName, object targetObj, object cellValue) { Type targetType = targetObj.GetType(); // 从缓存取属性映射,不存在则创建并缓存 if (!_propertyCache.TryGetValue(targetType, out var propMap)) { propMap = targetType.GetProperties() .ToDictionary(p => p.Name, p => p); _propertyCache[targetType] = propMap; } if (!propMap.TryGetValue(columnName, out var prop)) { Console.WriteLine($"目标对象中不存在名为 {columnName} 的属性"); return; } // 后续的类型转换与赋值逻辑和基础版一致 object valueToAssign = cellValue == DBNull.Value ? GetDefaultValue(prop.PropertyType) : cellValue; try { object convertedValue = Convert.ChangeType(valueToAssign, prop.PropertyType); prop.SetValue(targetObj, convertedValue); } catch (Exception ex) { Console.WriteLine($"列 {columnName} 的值转换失败:{ex.Message}"); } }
3. 特殊类型的针对性处理
遇到Nullable<T>、DateTime这类特殊类型时,需要额外适配:
// 在转换逻辑中添加特殊类型判断 object convertedValue; if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) { // 处理可空类型 Type underlyingType = Nullable.GetUnderlyingType(prop.PropertyType); convertedValue = cellValue == DBNull.Value ? null : Convert.ChangeType(cellValue, underlyingType); } else if (prop.PropertyType == typeof(DateTime)) { // 处理DateTime类型,兼容字符串格式的日期 if (cellValue is string dateStr) { if (DateTime.TryParse(dateStr, out var dateValue)) { convertedValue = dateValue; } else { throw new FormatException($"无法将字符串 {dateStr} 转换为DateTime类型"); } } else { convertedValue = Convert.ChangeType(cellValue, prop.PropertyType); } } else { convertedValue = Convert.ChangeType(valueToAssign, prop.PropertyType); }
额外优化建议
- 如果列名和属性名不一致,可以维护一个映射字典(比如
Dictionary<string, string>),把列名对应到目标属性名。 - 可以直接使用AutoMapper这类成熟的映射库,它内置了大量类型转换逻辑,能大幅减少手写代码的工作量:
// 配置AutoMapper映射规则 var config = new MapperConfiguration(cfg => cfg.CreateMap<DataRow, YourTargetType>()); IMapper mapper = config.CreateMapper(); // 遍历DataTable完成转换 foreach (DataRow row in inputTable.Rows) { YourTargetType obj = mapper.Map<YourTargetType>(row); // 后续处理转换后的对象 }
内容的提问来源于stack exchange,提问作者Roshan




