如何通过嵌套异步LINQ从XML提取子校准对象至列表
解决XML校准信息转Calibration列表的问题
嘿,我看你已经搞定了异步加载mks247设备的核心逻辑,现在卡在把XML里的校准数据绑定到设备实例上对吧?你之前尝试的写法报错,是因为LINQ的select子句后面需要跟一个表达式,不能直接用大括号写赋值逻辑。咱们来一步步解决这个问题:
方案1:修改创建方法,直接传入校准列表
这种方式最连贯,把校准数据的构造和设备创建整合在一起:
首先,调整你的LINQ查询,先用let关键字提前把当前设备下的校准元素转换成Calibration列表,再把这个列表传给创建方法:
var getmks247Task = from deviceElem in XDocument.Load(xmlRdr).Element("devices").Elements("device") where (string)deviceElem.Attribute("type") == "mks247" // 提前构造校准列表,注意类型转换(根据你的Calibration类调整) let calibrations = deviceElem.Elements("calibration") .Select(c => new Calibration { Name = (string)c.Attribute("name"), Unit = (string)c.Attribute("unit"), A = (double)c.Attribute("a"), // 如果a是整数就用(int) B = (double)c.Attribute("b") }).ToList() select CreateAndConnectTomks247Async( (string)deviceElem.Attribute("ip"), (string)deviceElem.Attribute("name"), (string)deviceElem.Attribute("id"), (bool)deviceElem.Attribute("autoconnect"), calibrations); // 把校准列表传进去 var mks247s = await Task.WhenAll(getmks247Task);
然后修改CreateAndConnectTomks247Async方法,新增校准列表参数,并且在方法内给设备的Calibrations属性赋值(顺便转成ObservableCollection解决你的次要问题):
private async Task<mks247Device> CreateAndConnectTomks247Async( string host, string name, string id, bool autoconnect = true, List<Calibration> calibrations = null) // 新增可选参数 { mks247Device dev = new mks247Device(host, name, id); // 赋值校准列表,转成ObservableCollection(如果你的设备属性是这个类型) dev.Calibrations = calibrations != null ? new ObservableCollection<Calibration>(calibrations) : new ObservableCollection<Calibration>(); if (autoconnect) { if (await dev.ConnectAsync()) dev.BeginPolling(); } return dev; }
方案2:不修改原方法,await后再赋值校准列表
如果不想改动原方法的签名,可以先异步获取所有设备,再遍历设备和对应的XML元素,给每个设备手动赋值校准信息:
// 先筛选出所有mks247类型的设备元素,存起来后续用 var deviceElems = XDocument.Load(xmlRdr).Element("devices").Elements("device") .Where(d => (string)d.Attribute("type") == "mks247") .ToList(); // 异步创建并连接设备 var tasks = deviceElems.Select(elem => CreateAndConnectTomks247Async( (string)elem.Attribute("ip"), (string)elem.Attribute("name"), (string)elem.Attribute("id"), (bool)elem.Attribute("autoconnect"))); var mks247s = await Task.WhenAll(tasks); // 遍历设备,给每个设备绑定校准信息 for (int i = 0; i < mks247s.Length; i++) { var currentElem = deviceElems[i]; var calibrations = currentElem.Elements("calibration") .Select(c => new Calibration { Name = (string)c.Attribute("name"), Unit = (string)c.Attribute("unit"), A = (double)c.Attribute("a"), B = (double)c.Attribute("b") }).ToList(); // 转成ObservableCollection赋值 mks247s[i].Calibrations = new ObservableCollection<Calibration>(calibrations); }
注意事项
- 确保类型转换正确:XML属性值默认是字符串,要根据
Calibration类的属性类型(比如int、double)做对应的转换,不要直接用Value取字符串; - 如果你的
Calibration类属性名和XML属性名不一致(比如XML里是a,类里是A),要对应好赋值关系; - 关于
ObservableCollection:直接用列表构造函数传入即可,它会自动把列表元素转成可观察集合。
内容的提问来源于stack exchange,提问作者AndreasN
相关产品推荐
相关产品推荐

