使用构造函数创建泛型T对象列表时抛出‘未找到System.RuntimeType构造函数’异常
嘿,这个需求我熟!咱们来一步步实现这个通用的列表转换方法,把DataTable的每一行都转成对应的模型对象~
核心思路
我们需要做的就是遍历DataTable的每一行,利用反射找到模型类中接收DataRow的构造函数,然后用该行数据实例化模型对象,最后把所有对象收集到List<T>里返回。为了让代码更健壮,我们还要加一些校验,确保目标类型确实有符合要求的构造函数。
基础版本代码
先写一个最直观的实现,逻辑清晰,适合快速验证:
public List<T> GenerateResultList<T>(DataTable dataTable) where T : class { var resultList = new List<T>(); if (dataTable == null || dataTable.Rows.Count == 0) return resultList; // 获取T类型中接收DataRow的构造函数 var constructor = typeof(T).GetConstructor(new[] { typeof(DataRow) }); if (constructor == null) { throw new InvalidOperationException($"类型 {typeof(T).Name} 必须包含一个接收单个DataRow参数的公共构造函数!"); } // 遍历每一行,实例化对象并加入列表 foreach (DataRow row in dataTable.Rows) { var modelInstance = (T)constructor.Invoke(new object[] { row }); resultList.Add(modelInstance); } return resultList; }
性能优化:缓存构造函数
如果这个方法会被频繁调用,每次反射获取构造函数会有点性能损耗。我们可以加个静态字典缓存已经获取过的构造函数,后续调用直接复用:
// 静态字典缓存构造函数,避免重复反射 private static readonly Dictionary<Type, ConstructorInfo> _constructorCache = new Dictionary<Type, ConstructorInfo>(); public List<T> GenerateResultList<T>(DataTable dataTable) where T : class { var resultList = new List<T>(); if (dataTable == null || dataTable.Rows.Count == 0) return resultList; Type targetType = typeof(T); // 先从缓存取,没有再反射获取 if (!_constructorCache.TryGetValue(targetType, out var constructor)) { constructor = targetType.GetConstructor(new[] { typeof(DataRow) }); if (constructor == null) { throw new InvalidOperationException($"类型 {targetType.Name} 必须包含一个接收单个DataRow参数的公共构造函数!"); } _constructorCache[targetType] = constructor; } foreach (DataRow row in dataTable.Rows) { var modelInstance = (T)constructor.Invoke(new object[] { row }); resultList.Add(modelInstance); } return resultList; }
使用示例
假设我们有一个用户模型类,构造函数接收DataRow并绑定字段:
public class UserModel { public string Username { get; set; } public int Age { get; set; } public DateTime RegisterDate { get; set; } // 必须有这个接收DataRow的构造函数 public UserModel(DataRow row) { // 注意处理DBNull的情况,避免转换出错 Username = row["Username"] is DBNull ? string.Empty : row["Username"].ToString(); Age = row["Age"] is DBNull ? 0 : Convert.ToInt32(row["Age"]); RegisterDate = row["RegisterDate"] is DBNull ? DateTime.MinValue : Convert.ToDateTime(row["RegisterDate"]); } }
然后调用方法就很简单了:
// 假设这是你的数据源DataTable DataTable userDataTable = GetUserDataTable(); // 转换为模型列表 List<UserModel> userList = GenerateResultList<UserModel>(userDataTable);
注意事项
- 确保模型类的构造函数是公共的,否则
GetConstructor会找不到(如果非要用非公共构造,可以在获取时加上BindingFlags.NonPublic | BindingFlags.Instance参数) - 模型构造函数里要处理
DBNull的情况,避免转换异常 - 如果传入的
DataTable为空或没有行,方法会返回空的List<T>,符合常规预期
内容的提问来源于stack exchange,提问作者ricky
相关产品推荐
相关产品推荐

