c# - 将对象转换为 System.Text.Json.JsonElement
问题描述
假设我有一个类型的对象:
public class MyClass
{
public string Data { get; set; }
}
我需要将其转换为 System.Text.Json.JsonElement。我找到的唯一方法是:
var json = JsonSerializer.Serialize(new MyClass { Data = "value" });
using var document = JsonDocument.Parse(json);
var jsonElement = document.RootElement;
我必须先序列化它然后解析它,这似乎很奇怪。有更好的方法吗?
以前我是JObject
从 Newtonsoft.Json 使用的,我可以这样做:
var jobject = JObject.FromObject(new MyClass { Data = "value" });
解决方案
In .NET 6 methods are being added to JsonSerializer
to serialize an object directly to a JsonElement
or JsonDocument
:
public static partial class JsonSerializer
{
public static JsonDocument SerializeToDocument<TValue>(TValue value, JsonSerializerOptions? options = null);
public static JsonDocument SerializeToDocument(object? value, Type inputType, JsonSerializerOptions? options = null);
public static JsonDocument SerializeToDocument<TValue>(TValue value, JsonTypeInfo<TValue> jsonTypeInfo);
public static JsonDocument SerializeToDocument(object? value, Type inputType, JsonSerializerContext context);
public static JsonElement SerializeToElement<TValue>(TValue value, JsonSerializerOptions? options = null);
public static JsonElement SerializeToElement(object? value, Type inputType, JsonSerializerOptions? options = null);
public static JsonElement SerializeToElement<TValue>(TValue value, JsonTypeInfo<TValue> jsonTypeInfo);
public static JsonElement SerializeToElement(object? value, Type inputType, JsonSerializerContext context);
}
Thus in .NET 6 you will be able to do:
using var jsonDocument = JsonSerializer.SerializeToDocument(new MyClass { Data = "value" });
or
var jsonElement = JsonSerializer.SerializeToElement(new MyClass { Data = "value" });
Notes:
JsonSerializerContext
andJsonTypeInfo<T>
are newly exposed in .NET 6 and provide metadata about a set of types, or a single typeT
, that is relevant to JSON serialization. They are used when serializing using metadata and code generated at compile time. See Try the new System.Text.Json source generator for details.JsonDocument
isIDisposable
, and in fact must needs be disposed because, according to the docs:JsonDocument
builds an in-memory view of the data into a pooled buffer. Therefore, unlikeJObject
orJArray
from Newtonsoft.Json, theJsonDocument
type implementsIDisposable
and needs to be used inside ausing
block.In your sample code you do not dispose of the document returned by
JsonDocument.Parse()
, but you should.The new methods should be present in .NET 6 RC1.
In .NET 5 and earlier a method equivalent to JObject.FromObject()
is not currently available out of the box in System.Text.Json
. There is an open enhancement about this, currently targeted for Future:
In the interim you may get better performance by serializing to an intermediate byte
array rather than to a string, since both JsonDocument
and Utf8JsonReader
work directly with byte
spans rather than strings or char
spans, like so:
public static partial class JsonExtensions
{
public static JsonDocument JsonDocumentFromObject<TValue>(TValue value, JsonSerializerOptions options = default)
=> JsonDocumentFromObject(value, typeof(TValue), options);
public static JsonDocument JsonDocumentFromObject(object value, Type type, JsonSerializerOptions options = default)
{
var bytes = JsonSerializer.SerializeToUtf8Bytes(value, type, options);
return JsonDocument.Parse(bytes);
}
public static JsonElement JsonElementFromObject<TValue>(TValue value, JsonSerializerOptions options = default)
=> JsonElementFromObject(value, typeof(TValue), options);
public static JsonElement JsonElementFromObject(object value, Type type, JsonSerializerOptions options = default)
{
using var doc = JsonDocumentFromObject(value, type, options);
return doc.RootElement.Clone();
}
}
And then call it like:
using var doc = JsonExtensions.JsonDocumentFromObject(new MyClass { Data = "value" });
Or, if you need to use the root element outside the scope of a using
statement:
var element = JsonExtensions.JsonElementFromObject(new MyClass { Data = "value" });
Notes:
As noted above, a
JsonDocument
needs to be disposed after being created. The aboveJsonExtensions.JsonElementFromObject()
extension methods correctly dispose of their internal document and returns a clone of the root element, as recommended in the documentation.Serializing to an intermediate Utf8 byte sequence is likely to be more performant than serializing to a
string
because, according to the docs:Serializing to UTF-8 is about 5-10% faster than using the string-based methods. The difference is because the bytes (as UTF-8) don't need to be converted to strings (UTF-16).
For the inverse method, see System.Text.Json.JsonElement ToObject workaround.
Demo fiddle here.
推荐阅读
- c# - 从 Web 表单的 Page_Load 调用异步方法
- robotframework - 有时 winium 在我的代码中给出 NoSuchElementException
- python - 列表追加附加比预期更多的值
- google-chrome - Chrome 网络请求不显示 Cookie 选项卡、一些请求标头、复制为 cURL 已损坏
- java - 带有 Openjdk8 的 Oracle sqldeveloper
- node.js - ValidationPipe 在使用 app.useGlobalPipes 时不起作用
- javascript - 为什么我不能在 for 循环中有一个 for 循环?
- java - 将树(非二进制)转换为路径列表
- c# - 如何在 C# 中搜索和替换 xml 文件定义
- swift - 从字符串转换为整数问题