LP1*_*P13 11 c# .net-5 system.text.json
我有一个属性类型为 的 DTO 类JObject
。此 DTO 类在多个服务之间通过 HTTP 发送/接收。使用 JObject 是因为ExtractedData
它没有预定义的属性
public class MyDTO
{
public JObject ExtractedData {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
我正在将此项目转换为 .NET 5。什么相当于 .NET 5 中的 JObject?我试图避免 JsonDocument 因为(来自文档):
JsonDocument 将数据的内存视图构建到池化缓冲区中。因此,与 Newtonsoft.Json 中的 JObject 或 JArray 不同,JsonDocument 类型实现 IDisposable 并且需要在 using 块中使用。
我打算使用JsonElement
. 这是最合适的选择还是有任何其他类型可用于将 JSON 作为对象保存?
hal*_*ldo 102
自 2021 年 11 月起,.NET 6
引入了System.Text.Json.Nodes命名空间,其中:
提供用于处理内存中可写文档对象模型 (DOM) 的类型,以便随机访问数据结构化视图中的 JSON 元素
这四种新类型是JsonArray
、JsonObject
、JsonNode
和JsonValue
。最接近的类型JObject
是JsonObject
提供类似功能的类型。
请参阅下面的一些示例:
// create object manually using initializer syntax
JsonObject obj = new JsonObject
{
["Id"] = 3,
["Name"] = "Bob",
["DOB"] = new DateTime(2001, 02, 03),
["Friends"] = new JsonArray
{
new JsonObject
{
["Id"] = 2,
["Name"] = "Smith"
},
new JsonObject
{
["Id"] = 4,
["Name"] = "Jones"
}
}
};
// random access to values
int id = (int)obj["Id"];
DateTime dob = (DateTime)obj["DOB"];
string firstFriendName = (string)obj["Friends"][0]["Name"];
Run Code Online (Sandbox Code Playgroud)
下面列出了一些其他很酷的东西,现在使使用System.Text.Json
变得更加容易.NET6
。
解析、创建和 DOM 操作
// parse
var jsonObj = JsonNode.Parse(jsonString).AsObject();
Run Code Online (Sandbox Code Playgroud)
如果你有一个JsonElement
(可能在反序列化为dynamic
、object
或 后JsonElement
)你可以调用Create
,现在你就有了一个可导航且可写的 DOM 对象:
// create
JsonObject obj = JsonObject.Create(jsonElement);
Run Code Online (Sandbox Code Playgroud)
您可以添加/删除属性:
obj.Add("FullName", "Bob Smith");
bool successfullyRemoved = obj.Remove("Name");
Run Code Online (Sandbox Code Playgroud)
ContainsKey
使用and TryGetPropertyValue
(返回 a )安全地询问对象的特定键JsonNode
:
if (obj.ContainsKey("Hobbies"))
// do stuff
if (obj.TryGetPropertyValue("Hobbies", out JsonNode? node))
// do stuff with node
Run Code Online (Sandbox Code Playgroud)
项目和过滤数据
可以使用 Linq 来投影和过滤JsonObject
:
// select Keys
List<string> keys = obj.Select(node => node.Key).ToList();
// filter friends
var friends = obj["Friends"].AsArray()
.Where(n => (int)n.AsObject()["Id"] > 2);
Run Code Online (Sandbox Code Playgroud)
反序列化Json
现在可以轻松反序列化 Json 或反序列化 Json 的一部分。当我们只想从主对象反序列化部分 Json 时,这很有用。对于上面的示例,我们可以轻松地将好友列表反序列化为泛型List<Friend>
:
List<Friend> friends = obj["Friends"].AsArray().Deserialize<List<Friend>>();
Run Code Online (Sandbox Code Playgroud)
其中Deserilize<T>()
是 上的扩展方法JsonNode
。
连载
JsonObject
使用以下命令可以轻松序列化ToJsonString()
:
string s = obj.ToJsonString();
// write pretty json with WriteIndented
string s = obj.ToJsonString(new JsonSerializerOptions { WriteIndented = true }));
Run Code Online (Sandbox Code Playgroud)
JsonObject
在您的特定情况下,您可以在 DTO 中定义:
public class MyDTO
{
public JsonObject ExtractedData {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
最接近的等价物JObject
确实是JsonElement
这样,您可以按如下方式修改您的 DTO:
public class MyDTO
{
public JsonElement ExtractedData {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
无需担心处理任何文档,因为在内部,JsonElementConverter
used byJsonSerializer
返回非池化元素(通过在 .NET 5 中克隆该元素)。
但是,对应关系并不准确,因此请记住以下几点:
JsonElement
表示任何 JSON 值,因此最接近于JToken
not JObject
。由于JsonElement
是struct
不存在对应于JSON对象没有子类。如果要限制ExtractedData
为 JSON 对象,则需要在 setter 中进行检查:
public class MyDTO
{
JsonElement extractedData;
public JsonElement ExtractedData
{
get => extractedData;
set
{
if (value.ValueKind != JsonValueKind.Object
// && value.ValueKind != JsonValueKind.Null Uncomment if you want to allow null
)
throw new ArgumentException(string.Format("{0} is not a JSON object type", value.ValueKind));
extractedData = value;
}
}
}
Run Code Online (Sandbox Code Playgroud)
由于JsonElement
是结构,因此默认值不是null
。那么,它是什么?事实证明,default(JsonElement)
有ValueKind = JsonValueKind.Undefined
:
没有值(与 Null 不同)。
如果你试图序列这样的默认值JsonElement
与JsonSerializer
一个异常将被抛出。也就是说,如果你只是这样做
var json = JsonSerializer.Serialize(new MyDTO());
Run Code Online (Sandbox Code Playgroud)
然后System.InvalidOperationException: Operation is not valid due to the current state of the object.
抛出异常。
您有几个选项可以避免此问题:
在 .NET 5 中,您可以这样申请[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
:
public class MyDTO
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public JsonElement ExtractedData {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
这会导致ExtractedData
在序列化期间跳过未初始化的值。
在 .NET Core 3.xJsonIgnoreCondition
中不存在,因此您可以改为定义ExtractedData
为可空:
public class MyDTO
{
public JsonElement? ExtractedData {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
或者您可以将其初始化为 null,JsonElement
如下所示:
public class MyDTO
{
public JsonElement ExtractedData {get;set;} = JsonExtensions.Null;
}
public static class JsonExtensions
{
static readonly JsonElement nullElement = CreateNull();
public static JsonElement Null => nullElement;
static JsonElement CreateNull()
{
using var doc = JsonDocument.Parse("null");
return doc.RootElement.Clone();
}
}
Run Code Online (Sandbox Code Playgroud)
这两个选项都会导致 的未初始化值ExtractedData
序列化为null
。
另请参阅相关问题:
归档时间: |
|
查看次数: |
4758 次 |
最近记录: |