使用Google Places API时,foreach循环中从XElement向List添加数据仅覆盖[0]位置而非填充整个列表的问题排查
解决你的Google Places API数据覆盖问题
问题出在哪?
兄弟,你这个问题其实很典型——每次循环都把整个placeDetailsModel列表给替换掉了!看你代码里的这行:
placeDetailsModel = doc2.Descendants("result").Select(...).ToList();
每次foreach循环执行这句的时候,都会创建一个全新的List,把原来的列表完全覆盖。所以不管循环多少次,最后列表里只会剩下最后一次请求到的那一条数据(也就是索引[0]的位置)。
怎么改?
咱们只需要把「重新赋值列表」改成「往现有列表里添加元素」就行,给你两种靠谱的写法:
写法一:用AddRange批量添加
因为单个place_id的Place Details返回结果只有一条,所以可以把查询到的小列表直接合并到主列表里:
static void Main(string[] args) { string City_Name = "Gdańsk"; var doc = XElement.Load($"https://maps.googleapis.com/maps/api/place/textsearch/xml?key={key}&query=restaurants+in+{City_Name}&language=pl&fields=place_id"); List<PlaceIdModel> IdList = doc.Descendants("result").Select(n => new PlaceIdModel { PlaceId = n.Element("place_id").Value }).ToList(); List<PlaceDetailsModel> placeDetailsModel = new List<PlaceDetailsModel>(); foreach (var item in IdList) { var doc2 = XElement.Load($"https://maps.googleapis.com/maps/api/place/details/xml?key={key}&place_id={item.PlaceId}&language=pl&fields=name,vicinity,geometry/location,rating,website,opening_hours/weekday_text"); // 先把当前place_id的详情存到临时列表 var currentDetails = doc2.Descendants("result").Select(x => new PlaceDetailsModel { Name = x.Element("name").Value, Vicinity = x.Element("vicinity").Value, Rating = x.Element("rating")?.Value ?? "无评分", // 加空值判断,防止没有rating的场所报错 Website = x.Element("website")?.Value ?? "无官网", Lat = x.Element("geometry").Element("location").Element("lat").Value, Lng = x.Element("geometry").Element("location").Element("lng").Value, Opening_hours = x.Descendants("weekday_text").Select(y => y.Value).ToList() }).ToList(); // 把临时列表里的元素添加到主列表,而不是替换主列表 placeDetailsModel.AddRange(currentDetails); }; }
写法二:直接取单个元素添加
既然单个place_id只会返回一条结果,咱们可以直接取第一个元素,然后添加到主列表,这样更直观:
static void Main(string[] args) { string City_Name = "Gdańsk"; var doc = XElement.Load($"https://maps.googleapis.com/maps/api/place/textsearch/xml?key={key}&query=restaurants+in+{City_Name}&language=pl&fields=place_id"); List<PlaceIdModel> IdList = doc.Descendants("result").Select(n => new PlaceIdModel { PlaceId = n.Element("place_id").Value }).ToList(); List<PlaceDetailsModel> placeDetailsModel = new List<PlaceDetailsModel>(); foreach (var item in IdList) { var doc2 = XElement.Load($"https://maps.googleapis.com/maps/api/place/details/xml?key={key}&place_id={item.PlaceId}&language=pl&fields=name,vicinity,geometry/location,rating,website,opening_hours/weekday_text"); // 获取单个详情对象 var detail = doc2.Descendants("result").Select(x => new PlaceDetailsModel { Name = x.Element("name").Value, Vicinity = x.Element("vicinity").Value, Rating = x.Element("rating")?.Value ?? "无评分", Website = x.Element("website")?.Value ?? "无官网", Lat = x.Element("geometry").Element("location").Element("lat").Value, Lng = x.Element("geometry").Element("location").Element("lng").Value, Opening_hours = x.Descendants("weekday_text").Select(y => y.Value).ToList() }).FirstOrDefault(); // 确认获取到数据再添加,避免加null进去 if (detail != null) { placeDetailsModel.Add(detail); } }; }
额外提醒
- 空值处理:我给你加了
?.Value ?? "默认值"的判断,因为有些餐厅可能没有评分或者官网,直接访问Value会报空引用错误,这个一定要注意。 - API限流:Google Places API有请求次数限制,批量调用的时候最好加个小延迟(比如
Thread.Sleep(100)),不然容易被限流,导致请求失败。
内容的提问来源于stack exchange,提问作者larsx
相关产品推荐
相关产品推荐

