执行.NET C#代码时出现间歇性错误。以下是错误。
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'Newtonsoft.Json.Linq.JValue' does not contain a definition for 'value'
下面是我正在使用的代码-
dynamic obj = JsonConvert.DeserializeObject(response);
string value = obj.responseObject.value.token;
当我尝试执行上面的代码-时,我得到了这个错误
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'Newtonsoft.Json.Linq.JValue' does not contain a definition for 'value'
请帮忙,我们将不胜感激。非常感谢。
您的问题是您试图反序列化JSON,通常看起来如下所示:
{"responseObject" : { "value" : { "token" : "some token" } } }
通过使用Json.NET的动态运行时绑定到Json属性:
dynamic obj = JsonConvert.DeserializeObject(response);
string value = obj.responseObject.value.token;
在您的代码工作的情况下,JSON包含您期望的属性和您期望的类型。但是,当您的JSON无法确认您期望的模式时——特别是"value"
的值是原子JSON值或null
而不是嵌套对象——那么Newtonsoft的动态绑定代码将失败,并显示您看到的错误。例如,给定以下两个JSON示例:
{"responseObject" : { "value" : "some atomic value such as an error message" } }
{"responseObject" : { "value" : null } }
则CCD_ 3将抛出CCD_。
在这里演示小提琴#1。
那么,对于解决方法,您有哪些选择?
dynamic
绑定有一个方便的语法,看起来很诱人,但当您使用dynamic
时,您将失去所有编译时的错误检查,并且当您的对象与您期望的不完全一样时,您经常会发现自己出现完全无法理解的错误。由于Json.NET的dynamic
反序列化实际上反序列化为LINQ到Json的JToken
层次结构,因此应该显式地这样做:
var obj = JsonConvert.DeserializeObject<JObject>(response);
现在要以容错方式访问obj.responseObject.value.token
,您的选项包括:
使用
SelectToken()
:var value = (string)obj.SelectToken("responseObject.value.token");
SelectToken()
比动态绑定更具容错性,并且如果指定路径上不存在令牌,则仅返回null
。使用
JTtoken
索引器并明确检查obj["responseObject"]?["value"]
是否为JSON对象:var value = (string)(obj["responseObject"]?["value"] as JObject)?["token"];
作为#2的变体,您可以引入一些扩展方法如下:
public static partial class JsonExtensions { public static JObject AsJObject(this JToken @in) => @in.As<JObject>(); public static TJToken As<TJToken>(this JToken @in) where TJToken : JToken => @in as TJToken; }
并执行:
var value = (string)obj["responseObject"].AsJObject()?["value"].AsJObject()?["token"];
您可以使用Json.NET Schema在解析之前验证Json。但是请注意,Json.NET Schema不是免费的。
演示小提琴#2,在此演示选项1-3。