如何在动态JSON中使用空条件运算符与JsonConvert.js

eqoofvh9  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(108)

我正在使用Newtonsoft对一个已知的JSON对象进行格式化,并从中检索一些值(如果它们存在的话)。
关键是对象结构可能会不断变化,所以我使用dynamic来遍历结构并检索值。由于对象结构不断变化,我使用空条件运算符来遍历JSON。
代码如下所示

dynamic jsonMeta = JsonConvert.DeserializeObject<dynamic>(jsonScript);
string gVal = jsonMeta.a?.b?.c?.d?.e?.f?.g?.Value ?? ""

这样做的全部思想是以空安全的方式遍历对象,这样如果成员不存在,它的计算结果为null,并为其分配一个默认值,而不会抛出异常。但是我看到的是,如果成员d是null,我会得到一个异常'Newtonsoft.Json.Linq.JValue' does not contain a definition for 'e'
我的理解是,虽然dValuenull,但它的类型是JValue,所以这就是null条件运算符不起作用的原因,但当它试图访问d内部的成员e时,它会抛出异常。
那么我的问题是如何在C#中实现这一点?有没有一种简单的方法可以访问JSON成员,而不需要知道JSON结构,或者是一种相对简单的方法?

xmd2e60i

xmd2e60i1#

不幸的是,由于NewtonSoftJSON.NET的设计限制,当将其用作动态转换时,它不能使用空合并或空条件运算符,正如我在上面的问题中所示的那样。
我发现的一个解决方案是使用System.Web.Helpers.Json,这个实现允许你做我上面试图做的事情,而不会遇到JSON.NET抛出的异常,因为它在运行时评估成员的方式导致了一种简单的方法来访问动态JSON结构的成员。另外,您不需要为成员引用Value,它是隐式的。

using System.Web.Helpers.Json

dynamic jsonMeta = Json.Decode(jsonString);
string gVal = jsonMeta.a?.b?.c?.d?.e?.f?.g ?? ""

但是,您需要根据您使用的Visual Studio版本单独安装程序集(这对于JSON.NET也是必需的)。使用VS 2019,只需通过IDE错误助手单击即可轻松安装它。关于它的更多细节在这里:Where can I find System.Web.Helpers, System.Web.WebPages, and System.Web.Razor?
Json.Decode的局限性是它不能处理重复的键(抛出异常),并且对它可以解析的字符数有最大限制(MaxJsonLength错误),这可以由inconvenient来修复。

wpx232ag

wpx232ag2#

另一种选择是使用dynamicExpandoObject,同时使用Newtonsoft.Json对JSON进行格式化。这允许您在动态对象上使用空条件运算符和空合并运算符。

dynamic jsonMeta = JsonConvert.DeserializeObject<ExpandoObject>(jsonScript, new ExpandoObjectConverter());
string gVal = jsonMeta.a?.b?.c?.d ?? ""

但是这有一个限制,* 如果它访问一个不存在的成员,ExpandoObject将抛出一个异常 *(它是一个密封的类,这个行为是硬编码的)。所以为了解决这个问题,我写了一个自定义的SafeExpandoObject类,它 Package 了ExpandoObject,允许你访问所有/不存在的成员而不会抛出异常,当你试图访问一个不存在的成员时,它会返回null
你可以在这里找到代码:https://codereview.stackexchange.com/questions/287243/wrapping-an-expandoobject-within-a-safeexpandoobject
这样使用:

dynamic jsonMeta = JsonConvert.DeserializeObject<ExpandoObject>(jsonScript, new ExpandoObjectConverter());
jsonMeta = new SafeExpandoObject(jsonMeta); // Rewrap the ExpandoObject in a SafeExpandoObject that doesn't throw exceptions
string gVal = jsonMeta.a?.b?.c?.d ?? ""

另一点需要注意的是,你不能像jsonMeta["@name"]那样使用ExpandoObject的直接索引。
要克服这个限制,您需要实现SafeExpandoObjectIDictionary接口,以允许直接索引,或者将ExpandoObject转换为IDictionary<string, object>,然后像下面这样索引它:

dynamic jsonMeta = JsonConvert.DeserializeObject<ExpandoObject>(jsonScript, new ExpandoObjectConverter());
string a = (jsonMeta as IDictionary<string, object>)["@name"];

相关问题