通过 dynamic 关键字轻松访问 Microsoft JSON DOM





5.00/5 (2投票s)
如果您正在使用 JSON 和 C# 构建模板或其他复杂结构,这可能是一个不错的解决方案。
引言
我不喜欢 JSON 和静态类型语言之间的极性不匹配。例如,在 Javascript 中,您可以像访问原生对象一样访问 JSON 数据——因为在 Javascript 中它们本质上就是原生对象。在使用 C# 时,您通常需要使用某种 DOM 或解析器来导航和访问 JSON 信息集中的数据。这会降低可读性并使您的代码变得笨拙。
C# 并非绝对需要这种限制,因为它具有 dynamic
关键字,可用于后期绑定。不幸的是,这样做会失去静态类型检查。因此,我将 JSON 对象设置为只读,以防止随意修改。这些的主要用途是在类似 ASP.NET 页面的场景中,正如我将演示的那样。
使用代码
首先,将以下代码复制到您项目中的一个新文件中
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Text;
using System.Text.Json;
class DynamicJsonElement : DynamicObject, IEnumerable<object?>
{
JsonElement _inner;
private static object? ElemToObj(JsonElement elem)
{
object? result = null;
switch (elem.ValueKind)
{
case JsonValueKind.String:
result = elem.GetString()!;
break;
case JsonValueKind.Number:
result = elem.GetDouble();
break;
case JsonValueKind.Null:
result = null;
break;
case JsonValueKind.True:
result = true; break;
case JsonValueKind.False:
result = false; break;
case JsonValueKind.Object:
case JsonValueKind.Array:
result = new DynamicJsonElement(elem);
break;
default:
result = null;
break;
}
return result;
}
public DynamicJsonElement(JsonElement json)
{
_inner = json;
}
public int Count
{
get
{
if (_inner.ValueKind == JsonValueKind.Array)
{
return _inner.GetArrayLength();
}
throw new NotSupportedException();
}
}
public object? this[int index]
{
get
{
if (_inner.ValueKind == JsonValueKind.Array)
{
return ElemToObj(_inner[index]);
}
throw new NotSupportedException();
}
}
public override bool TryGetMember(
GetMemberBinder binder, out object? result)
{
JsonElement elem;
if (_inner.TryGetProperty(binder.Name, out elem))
{
result = ElemToObj(elem);
return true;
}
result = null;
return false;
}
public override bool TrySetMember(
SetMemberBinder binder, object? value)
{
return false;
}
public IEnumerator<object?> GetEnumerator()
{
if (_inner.ValueKind == JsonValueKind.Array)
{
foreach (var elem in _inner.EnumerateArray())
{
yield return ElemToObj(elem);
}
}
else
{
throw new NotSupportedException();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
现在,每当您收到 JsonElement 时,都可以使用 new DynamicJsonElement(myJson)
包装它。
dynamic root = new DynamicJsonElement(JsonDocument.Parse(stream).RootElement);
从那里,root 是文档的根,您可以像在 Javascript 中一样访问字段和值
Console.WriteLine("{0} {1}",root.first_name,root.last_name);
Console.WriteLine("City: {0}",root.addresses[0].city);
请记住,您需要将获取到的值进行类型转换,因为它从其属性和访问器返回 object
。 上面我们不需要进行转换,因为 WriteLine()
可以接受 object
类型。
这在 T4 和 ASP.NET 模板中特别有用
<span>Age: <%=root.age%></span>
结果可读性大大提高。
一个需要注意的点是,在使用 foreach 循环时,必须将迭代的值重新赋值给一个动态对象,如所示
foreach(var item in root.addresses) {
dynamic address = item;
// now you can access address
}
历史
- 2024 年 4 月 4 日 - 初始提交