C#中如何从Dynamic对象获取Forecast节点的JSON数据值?
Hey, let's sort out this issue you're having with accessing the dynamic date-based keys in the forecast node. I see you've tried splitting deserialization into two steps with dynamic, but couldn't pull values from it—let's walk through both a clean, type-safe solution (my recommendation) and how to make your existing approach work.
Option 1: Adjust Your Model for Direct Deserialization (Best Practice)
Instead of deserializing twice, we can update your Weather model to use a Dictionary<string, ForecastDay> for the Forecast property. Newtonsoft.Json will automatically map those dynamic date keys to the dictionary's keys, and the values to your ForecastDay object.
First, here's the complete set of model classes (with proper JSON property mapping if you prefer PascalCase for C# properties):
public class Weather { public Request Request { get; set; } public Location Location { get; set; } public Current Current { get; set; } // Use Dictionary to handle dynamic date keys public Dictionary<string, ForecastDay> Forecast { get; set; } } public class Request { [JsonProperty("type")] public string Type { get; set; } [JsonProperty("query")] public string Query { get; set; } [JsonProperty("language")] public string Language { get; set; } [JsonProperty("unit")] public string Unit { get; set; } } public class Location { [JsonProperty("name")] public string Name { get; set; } [JsonProperty("country")] public string Country { get; set; } [JsonProperty("region")] public string Region { get; set; } [JsonProperty("lat")] public string Lat { get; set; } [JsonProperty("lon")] public string Lon { get; set; } [JsonProperty("timezone_id")] public string TimezoneId { get; set; } [JsonProperty("localtime")] public string LocalTime { get; set; } [JsonProperty("localtime_epoch")] public int LocalTimeEpoch { get; set; } [JsonProperty("utc_offset")] public string UtcOffset { get; set; } } public class Current { [JsonProperty("observation_time")] public string ObservationTime { get; set; } [JsonProperty("temperature")] public int Temperature { get; set; } [JsonProperty("weather_code")] public int WeatherCode { get; set; } [JsonProperty("weather_icons")] public List<string> WeatherIcons { get; set; } [JsonProperty("weather_descriptions")] public List<string> WeatherDescriptions { get; set; } [JsonProperty("wind_speed")] public int WindSpeed { get; set; } [JsonProperty("wind_degree")] public int WindDegree { get; set; } [JsonProperty("wind_dir")] public string WindDir { get; set; } [JsonProperty("pressure")] public int Pressure { get; set; } [JsonProperty("precip")] public int Precip { get; set; } [JsonProperty("humidity")] public int Humidity { get; set; } [JsonProperty("cloudcover")] public int Cloudcover { get; set; } [JsonProperty("feelslike")] public int FeelsLike { get; set; } [JsonProperty("uv_index")] public int UvIndex { get; set; } [JsonProperty("visibility")] public int Visibility { get; set; } [JsonProperty("is_day")] public string IsDay { get; set; } } public class ForecastDay { [JsonProperty("date")] public string Date { get; set; } [JsonProperty("date_epoch")] public int DateEpoch { get; set; } [JsonProperty("astro")] public Astro Astro { get; set; } [JsonProperty("mintemp")] public int MinTemp { get; set; } [JsonProperty("maxtemp")] public int MaxTemp { get; set; } [JsonProperty("avgtemp")] public int AvgTemp { get; set; } [JsonProperty("totalsnow")] public int TotalSnow { get; set; } [JsonProperty("sunhour")] public double SunHour { get; set; } [JsonProperty("uv_index")] public int UvIndex { get; set; } } public class Astro { [JsonProperty("sunrise")] public string Sunrise { get; set; } [JsonProperty("sunset")] public string Sunset { get; set; } [JsonProperty("moonrise")] public string Moonrise { get; set; } [JsonProperty("moonset")] public string Moonset { get; set; } [JsonProperty("moon_phase")] public string MoonPhase { get; set; } [JsonProperty("moon_illumination")] public int MoonIllumination { get; set; } }
Now you can deserialize once and access all data easily—including the forecast dates:
var weatherData = JsonConvert.DeserializeObject<Weather>(customerJsonString); // Iterate through all forecast days foreach (var dayKvp in weatherData.Forecast) { string date = dayKvp.Key; // e.g., "2020-05-28" ForecastDay dayData = dayKvp.Value; Console.WriteLine($"Date: {date}"); Console.WriteLine($"Max Temp: {dayData.MaxTemp}°C"); Console.WriteLine($"Sunrise: {dayData.Astro.Sunrise}"); } // Or get a specific day directly if you know the date if (weatherData.Forecast.TryGetValue("2020-05-28", out ForecastDay specificDay)) { Console.WriteLine($"Average Temp on 2020-05-28: {specificDay.AvgTemp}"); }
This approach is type-safe, avoids dynamic pitfalls, and keeps your code clean.
Option 2: Make Your Existing Dynamic/Dictionary Approach Work
If you don't want to adjust your model right now, you can fix your current code to access values correctly. The key thing to remember is that JSON property names are case-sensitive here—you need to match the exact lowercase keys from your JSON.
Here's how to pull values from your forecast_details dynamic object:
var dataObjects23 = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(customerJsonString); dynamic forecast_details = dataObjects23["forecast"]; // Option A: Loop through all forecast days foreach (var forecastEntry in forecast_details) { string dateKey = forecastEntry.Key; dynamic dayData = forecastEntry.Value; // Access properties using exact JSON names (lowercase) int maxTemp = dayData.maxtemp; string sunrise = dayData.astro.sunrise; Console.WriteLine($"Date: {dateKey}, Max Temp: {maxTemp}, Sunrise: {sunrise}"); } // Option B: Get a specific day's data directly dynamic targetDay = forecast_details["2020-05-28"]; int avgTemp = targetDay.avgtemp; string moonPhase = targetDay.astro.moon_phase; Console.WriteLine($"Avg Temp: {avgTemp}, Moon Phase: {moonPhase}");
Common Pitfalls to Check
If you're still not getting values with dynamic, double-check these:
- Case sensitivity: JSON keys are lowercase (e.g.,
maxtemp), so don't useMaxTempin your dynamic access. - JSON validity: Ensure the
forecastnode actually contains the date key you're trying to access—no typos in the date string. - Serialization settings: If you've modified
JsonSerializerSettings(like a custom contract resolver), it might be altering how keys are mapped.
内容的提问来源于stack exchange,提问作者rishi raj

