将Object类型转换为自定义类时遇System.InvalidCastException的优化方案咨询
我之前也踩过System.InvalidCastException这个强转的坑!直接强转(Event)obj只有当obj本身就是Event类的实例时才有效,如果它是匿名对象、SQLite返回的动态实体或者其他结构相似但类型不同的对象,强转肯定会炸。你用JsonConvert能解决是因为它通过序列化/反序列化重新构建了实例,但确实有性能开销,下面给你几个更优的替代方案:
1. 类型安全的直接转换(最高效)
如果你的obj本质上就是Event实例(比如从集合里取出来的、之前存进去的),那用is或as关键字做类型检查后再转换,既安全又没有额外开销:
// 方式1:C# 7.0+的模式匹配 if (obj is Event myEvent) { // 直接使用myEvent,无需再强转 } // 方式2:as关键字 var myEvent = obj as Event; if (myEvent != null) { // 使用myEvent }
这种方式比序列化快得多,而且编译时就能做类型检查,避免运行时异常。
2. 对象映射工具(适合频繁转换)
如果obj是结构相似的其他类型(比如DTO、匿名类、SQLite的动态对象),用AutoMapper这类映射工具是更优雅的选择,它能自动匹配同名同类型的属性,还支持自定义映射规则:
// 全局初始化一次(比如在Startup里) var mapperConfig = new MapperConfiguration(cfg => { cfg.CreateMap(obj.GetType(), typeof(Event)); // 如果有特殊属性需要映射,这里可以加规则,比如忽略某个属性 // cfg.CreateMap<SourceType, Event>().ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.SourceId)); }); var mapper = mapperConfig.CreateMapper(); // 转换时一行代码 var myEvent = mapper.Map<Event>(obj);
AutoMapper的性能比JsonConvert好,而且类型更安全,适合项目中频繁需要对象转换的场景。
3. 反射手动赋值(无第三方依赖)
如果不想引入第三方库,且对象结构简单,用反射手动遍历属性赋值也是可行的:
var myEvent = new Event(); var sourceProps = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); var targetProps = typeof(Event).GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var sourceProp in sourceProps) { var targetProp = targetProps.FirstOrDefault(p => p.Name.Equals(sourceProp.Name, StringComparison.OrdinalIgnoreCase) && p.PropertyType.IsAssignableFrom(sourceProp.PropertyType)); if (targetProp != null && targetProp.CanWrite) { targetProp.SetValue(myEvent, sourceProp.GetValue(obj)); } }
这种方式不需要额外依赖,但代码相对繁琐,适合小范围、简单对象的转换。
为什么JsonConvert能解决问题?
JsonConvert.SerializeObject(obj) + JsonConvert.DeserializeObject<Event>()的本质是把对象序列化成JSON字符串,再重新反序列化成Event实例——相当于绕过了类型检查,只要属性结构匹配就能生成新的Event对象。但这种方式有明显的性能开销,而且如果你的Event类有SQLite的特殊属性(比如[PrimaryKey]、[Column]),可能需要配置JsonConverter来处理,否则可能丢失属性信息。
总结选择建议:
- 如果
obj本身就是Event实例:优先用类型安全的直接转换 - 如果是不同类型但结构相似的对象:优先用AutoMapper
- 不想加依赖且对象简单:用反射手动赋值
- 快速解决通用场景:用
JsonConvert(作为兜底方案)
内容的提问来源于stack exchange,提问作者Bug Hunter Zoro

