DB映射中如何将Object值动态转换为实体属性的目标类型?
解决SqlDataReader映射中可空值类型跨类型赋值的问题
这个问题我之前也踩过坑——反射调用属性赋值时,可空值类型的跨类型隐式转换不会自动生效,导致找不到对应的set方法。咱们来一步步解决它:
问题本质
当数据库返回的是包装在object里的short?(对应smallint类型),要赋值给实体的int?属性时,直接用InvokeMember会报错,因为反射会严格匹配参数类型:它会寻找接受short?的属性set方法,但你的属性实际接受的是int?,反射不会自动处理这种跨可空值类型的转换。
方案1:用Convert.ChangeType处理可空类型
我们可以先解析目标属性的底层类型,再显式转换值,最后赋值:
void Main() { // 模拟SqlDataReader返回的short?包装为object object s = (short?)1; MyClass newObjectToReturn = Activator.CreateInstance<MyClass>(); // 获取目标属性的元信息 var targetProp = newObjectToReturn.GetType() .GetProperties() .First(prop => prop.Name == "MyProperty"); // 处理可空类型:如果是Nullable<T>,拿到它的底层T类型 Type targetUnderlyingType = Nullable.GetUnderlyingType(targetProp.PropertyType) ?? targetProp.PropertyType; // 转换值:先把object拆箱并转换为目标底层类型,再自动包装回可空类型 object convertedValue = Convert.ChangeType(s, targetUnderlyingType); // 用PropertyInfo.SetValue替代InvokeMember,更直观 targetProp.SetValue(newObjectToReturn, convertedValue); // 验证结果 Console.WriteLine(newObjectToReturn.MyProperty); // 输出1 } class MyClass { public int? MyProperty { get; set; } }
方案2:用dynamic简化转换逻辑
如果你的项目支持C# 4.0及以上,dynamic可以帮我们自动处理可空值类型的转换,代码更简洁:
void Main() { object s = (short?)1; MyClass newObjectToReturn = Activator.CreateInstance<MyClass>(); var targetProp = newObjectToReturn.GetType() .GetProperties() .First(prop => prop.Name == "MyProperty"); // 用dynamic自动处理拆箱和类型转换 dynamic dynamicValue = s; targetProp.SetValue(newObjectToReturn, dynamicValue); Console.WriteLine(newObjectToReturn.MyProperty); // 输出1 } class MyClass { public int? MyProperty { get; set; } }
为什么原代码会报错?
原代码中直接把object类型的s传入InvokeMember,反射会尝试匹配参数类型为short?的set方法,但你的MyProperty的set方法接受的是int?,反射不会自动执行隐式转换,所以抛出了"Method not found"异常。而手动转换或用dynamic时,我们先把值转换成了目标类型,反射就能找到对应的属性设置方法了。
内容的提问来源于stack exchange,提问作者Royi Namir
相关产品推荐
相关产品推荐

