C#动态ExpandoObject存在成员却抛出‘未包含定义’异常,求解决
解决Flurl返回ExpandoObject访问成员时的RuntimeBinderException问题
我太懂你这种明明看着字段存在却访问不了的憋屈了!明明API返回的JSON里Id和Name清清楚楚,用dynamic遍历的时候却突然抛出RuntimeBinderException说ExpandoObject没有这些定义,其实这问题和动态类型的绑定机制以及Flurl的反序列化行为有关,咱们来一步步搞定它:
最推荐的解决方案:直接反序列化为强类型列表
完全不用绕dynamic的弯路,Flurl本身就支持直接把API响应反序列化成你定义的Model类型列表,代码简洁还自带类型安全:
// 一步到位,省去手动转换的麻烦 List<Model> modelList = await GetApiUrl("EndpointName").GetJsonAsync<List<Model>>();
不过这里要注意:你的Model属性是GuidId,但JSON里对应的字段是Id,需要给Model加个特性做字段映射:
public class Model { [JsonProperty("Id")] // 告诉序列化器对应JSON里的Id字段 public Guid GuidId { get; set; } public string Name { get; set; } }
加上这个特性后,反序列化就能自动把JSON的Id赋值给GuidId,完美解决问题,还彻底避开动态类型的各种坑。
如果一定要用dynamic的替代方案
要是你因为某些原因必须保留dynamic的处理方式,那可以利用ExpandoObject实现了IDictionary<string, object>这个特性,强制转换后通过字典键访问成员:
IList<dynamic> list = await GetApiUrl("EndpointName").GetJsonListAsync(); List<Model> modelList = new List<Model>(); foreach(var item in list) { // 把dynamic转换成字典绕开动态绑定问题 var expandoDict = item as IDictionary<string, object>; var model = new Model() { GuidId = new Guid(expandoDict["Id"].ToString()), Name = expandoDict["Name"].ToString() }; modelList.Add(model); }
这种方式直接通过字典键取值,可靠性比动态绑定高很多。
为什么原来的代码会报错?
虽然ExpandoObject在运行时确实包含Id和Name这些动态成员,但在异步方法的foreach循环场景下,C#的动态绑定上下文可能出现识别问题——编译器没办法在编译时确认这些成员的存在,而运行时的绑定逻辑有时候会因为异步状态的变化,无法正确解析ExpandoObject的动态成员,最终导致抛出异常。
内容的提问来源于stack exchange,提问作者Kruno MONO
相关产品推荐
相关产品推荐

