将对象转换为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;

我必须先序列化它,然后再解析它,这似乎很奇怪。有更好的方法吗?

以前我使用Newtonsoft的JObject。Json和我可以这样做:

var jobject = JObject.FromObject(new MyClass { Data = "value" });

In.NET 6方法被添加到JsonSerializer,以将对象直接序列化到JsonElementJsonDocument:

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);
}

因此,在.NET6中,您将能够做到:

using var jsonDocument = JsonSerializer.SerializeToDocument(new MyClass { Data = "value" });

var jsonElement = JsonSerializer.SerializeToElement(new MyClass { Data = "value" });

注:

  • JsonSerializerContextJsonTypeInfo<T>是.NET 6中新公开的,它们提供与JSON序列化相关的一组类型或单个类型T的元数据。它们在使用元数据和编译时生成的代码进行序列化时使用。有关详细信息,请参阅尝试新的System.Text.Json源生成器。

  • JsonDocumentIDisposable,事实上必须被处理,因为根据文档:

    JsonDocument将数据的内存视图构建到池缓冲区中。因此,与Newtonsoft.Json的JObjectJArray不同,JsonDocument类型实现IDisposable,并且需要在using块内部使用。

    在示例代码中,您不会处理JsonDocument.Parse()返回的文档,但应该处理。

  • 新方法应该出现在.NET 6 RC1中。

在.NET 5及更早版本中,等效于JObject.FromObject()的方法目前在System.Text.Json中不可用。这方面有一个开放的增强功能,目前针对Future:

  • 我们应该能够从DOM#31274进行序列化和序列化

在此期间,您可以通过序列化到中间byte数组而不是字符串来获得更好的性能,因为JsonDocumentUtf8JsonReader都直接使用byte跨度,而不是字符串或char跨度,如下所示:

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();
}
}

然后称之为:

using var doc = JsonExtensions.JsonDocumentFromObject(new MyClass { Data = "value" });

或者,如果您需要在using语句的范围之外使用根元素:

var element = JsonExtensions.JsonElementFromObject(new MyClass { Data = "value" });

注:

  • 如上所述,JsonDocument需要在创建后进行处理。上面的JsonExtensions.JsonElementFromObject()扩展方法正确地处理了它们的内部文档,并返回根元素的克隆,如文档中所建议的那样。

  • 序列化到中间的Utf8字节序列可能比序列化到string更具性能,因为根据文档:

    序列化到UTF-8比使用基于字符串的方法快大约5-10%。区别在于字节(UTF-8(不需要转换为字符串(UTF-16(。

  • 有关反向方法,请参见System.Text.Json.JsonElement ToObject解决方法

在这里演示小提琴。

.NET 5中的一种巧妙方法是:

private JsonElement JsonElementFromObject(object value)
{
var jsonUtf8Bytes = JsonSerializer.SerializeToUtf8Bytes(value, new JsonSerializerOptions());
using var doc = JsonDocument.Parse(jsonUtf8Bytes);
return doc.RootElement.Clone();
}

步骤:

  1. 将值转换为JSON字符串,编码为UTF-8字节(SerializeToUtf8Bytes(
  2. 解析JSON字符串(JsonDocument.Parse(
  3. 返回根元素

dbc的答案是一个很好的开始,但如果对象值已经是json字符串,则还不够!此外,他的代码中没有使用该类型。

因此,我提出以下改进版本:

public static JsonDocument JsonDocumentFromObject(object value, JsonSerializerOptions options = null)
{
if (value is string valueStr)
{
try { return JsonDocument.Parse(valueStr); }
catch {}
}
byte[] bytes = JsonSerializer.SerializeToUtf8Bytes(value, options);
return JsonDocument.Parse(bytes);
}
public static JsonElement JsonElementFromObject(object value, JsonSerializerOptions options = null)
{
JsonElement result;
using (JsonDocument doc = JsonDocumentFromObject(value, options))
{
result = doc.RootElement.Clone();
}
return result;
}

使用以下单元测试(xUnit(:

[Fact()]
public void JsonElementFromObjectTest()
{
object o = new
{
id = "myId",
timestamp = DateTime.UtcNow,
valid = true,
seq = 1
};
JsonElement element1 = JsonSerializerExtension.JsonElementFromObject(o);
Assert.Equal(JsonValueKind.Object, element1.ValueKind);
string oStr1 = element1.GetRawText();
Assert.NotNull(oStr1);
JsonElement element2 = JsonSerializerExtension.JsonElementFromObject(oStr1);
Assert.Equal(JsonValueKind.Object, element2.ValueKind);
string oStr2 = element2.GetRawText();
Assert.NotNull(oStr2);
Assert.Equal(oStr1, oStr2);
}

如果没有直接的tryParse,element2是JsonValueKind.String,而oStr2包含未转义的unicode字符,因此是无效的Json字符串。

最新更新