C#中List<Sensor>转List<IntSensor/ExtSensor>技术问题求助
问题分析与解决方案
兄弟,我一眼就看出问题核心了——你在ParseJsonData.GetSensors方法里创建的全是基类Sensor的实例,而不是IntSensor或者ExtSensor的子类实例!这就好比你造了一堆普通轿车,现在想直接把它们当成跑车用,肯定行不通,因为它们从本质上就不是跑车类型。
为什么你之前的转换尝试全失败了?
Cast<IntSensor>():这个方法是强制把集合里的每个元素当成IntSensor,但你的元素实际类型是Sensor,类型不兼容,运行时会直接抛出InvalidCastException。ConvertAll(instance => (IntSensor)instance):和Cast逻辑一致,强制转换基类实例为子类,同样会因为对象实际类型不匹配而失败。OfType<IntSensor>():这个方法是筛选集合中本来就是IntSensor类型的元素,你的集合里全是Sensor,自然返回空列表。
方案一:解析时直接生成对应子类实例(推荐)
修改GetSensors方法,让它根据需求创建指定子类的实例,后续就不需要任何转换操作了。
修改后的ParseJsonData类:
public class ParseJsonData { public static Device GetRoomAlertModel(JObject jsonTree) { Device model = new Device(); model.IP = jsonTree["ip"].ToString(); model.Name = jsonTree["name"].ToString(); return model; } // 泛型方法,直接创建指定子类的传感器实例 public static List<T> GetSensors<T>(JToken jToken) where T : Sensor, new() { var sensors = new List<T>(); try { foreach (var item in jToken) { var s = new T(); // 这里创建的是子类实例 s.Name = item["lab"].ToString(); s.ActualTemp = item["tf"] != null ? item["tf"].ToString() : ""; s.HighTemp = item["hf"] != null ? item["hf"].ToString() : ""; s.LowTemp = item["lf"] != null ? item["lf"].ToString() : ""; sensors.Add(s); } } catch (Exception) { } return sensors; } }
然后在仓储类中直接调用:
public class RoomAlertRepository { internal Device Retreive() { var filePath = HostingEnvironment.MapPath(@"~/App_Data/RoomAlertsData.json"); var json = File.ReadAllText(filePath); JObject jsonTree = JObject.Parse(json); var internalSensorTree = jsonTree["internal_sen"]; var externalSensorTree = jsonTree["sensor"]; var model = ParseJsonData.GetRoomAlertModel(jsonTree); // 直接获取IntSensor列表,无需转换 model.InternalSensors = ParseJsonData.GetSensors<IntSensor>(internalSensorTree); // 同理获取ExtSensor列表 model.ExternalSensors = ParseJsonData.GetSensors<ExtSensor>(externalSensorTree); return model; } }
方案二:手动映射基类属性到子类(兼容现有代码)
如果暂时不能修改GetSensors方法,你可以手动把基类对象的属性值复制到新的子类实例中,而不是直接强制转换:
仓储类中的代码修改为:
var baseList = ParseJsonData.GetSensors(internalSensorTree); model.InternalSensors = baseList.Select(s => new IntSensor { Name = s.Name, ActualTemp = s.ActualTemp, HighTemp = s.HighTemp, LowTemp = s.LowTemp }).ToList();
这种方式虽然需要逐个复制属性,但能解决当前问题,适合基类属性不多的场景。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

