JsonSerializer.Parse(String, Type, JsonSerializerOptions)
支持动态ExpandoObject
返回类型?
像这样的东西:
dynamic p = JsonSerializer.Parse(json, typeof(ExpandoObject));
不,此时不支持此功能,但我们应该为 vNext 考虑。 您是否有示例用法来激发功能请求?
标记为未来。
System.NotSupportedException : The collection type 'System.Dynamic.ExpandoObject' is not supported.
@ahsonkhan GraphQL 就是一个很好的例子。
该规范推荐使用 JSON,但它与响应中的任何特定序列化无关。
这意味着响应的“数据”字段属于以下类型:动态。 因为无法推断。
如果没有 ExpandoObject,反序列化使动态成为 JSON 制作的一种类型。 所以访问抽象的动态“数据”必须知道动态实际上是一个 JToken。
使用 ExpandoObject 我认为我们可以像普通对象一样强制访问动态“数据”
@ahsonkhan另一个例子是我们项目中的配置服务。 它像 REST 端点一样公开集合,这些端点在 MongoDB 中创建集合(它不仅仅是一个虚拟的 REST 包装器,并且休息集合和 mongo 集合没有精确的 1-1 映射,它还断言某些规则)。
所以在我们的项目中我们需要动态/ExpandoObject 支持。
我们也在其他微服务中使用它。
我们也遇到了这个限制。 我们的用例是在json序列化之前逐步构建一个动态对象。 回到更成熟的 Json.NET 序列化器。
大家好
什么是散步呢?
我可以配置使用哪一个吗?
@SidShetye你说了一些关于回到更成熟的事情,你能解释一下吗?
@MickeyReznikov :见https://stackoverflow.com/questions/15455304/deserialize-a-property-as-an-expandoobject-using-json-net或谷歌“json.net expandoobject”
@MickeyReznikov ,您的问题得到解答了吗? 我相信@SidShetye意味着要重新使用Newtonsoft.Json
来序列化动态对象,因为内置库 (System.Text.Json) 尚不支持这些动态对象。 对于 asp.net 应用程序,您可以将其配置为 AddNewtonsoftJson。
我也有一个用例 - 我只想使用 HttpClient 调用 REST API 并从响应中检索单个属性。 我不想创建一个专门的类来解析响应......使用 JSON.NET 我可以只使用“动态”并访问选择的属性。
来自https://github.com/dotnet/corefx/issues/41472 @ghost1372 :
嗨,我希望这是问这个问题的好地方
似乎我们不能反序列化动态对象
我使用了这段代码但没有用 有什么办法可以做到这一点吗?var objList = System.Text.Json.JsonSerializer.Deserialize<List<dynamic>>(json);
在许多应用程序中,我们控制来自存储过程的数据字段,并使用 jquery.jtable 动态呈现列表和搜索列表页面
如果没有对 ExpandoObject 的 JsonSerializer 内置支持,我们将无法使用 dotnet 核心内置的 Json 序列化
我们确实共享了@estiller和@SidShetye 已经提到的相同用例
与此同时,我们不得不切换回 Json.NET。
是否有可能比Future更接近 _now_ 的里程碑? 🤔
ExpandoObject 已经在 BCL 中出现了很长时间
ExpandoObject 有什么替代方案吗?
@fatihyildizhan不,没有替代品。
但是我们已经编写了自己的 ExpandoObject 转换器,您可以从这篇文章ASP.NET Core 3.0:用于新 System.Text.Json 的自定义 JsonConverter 中得到提示
我们只需要序列化,所以我们只需要创建序列化
我很惊讶这还不支持。
将其移至 5.0。
迁移到 5.0? 也就是说至少要等一年? 回到 JSON.Net,它是。
5.0? 哇,这绝对糟透了。
对于临时丑陋的解决方法,我可以使用带有自定义转换器的 JsonDocument,但它是 IDisposable。
public sealed class EventObject
{
[JsonPropertyName("id")]
public long Id
{
get; set;
}
[JsonPropertyName("eventData")]
[JsonConverter(typeof(JsonDocumentConverter))]
public System.Text.Json.JsonDocument EventData
{
get; set;
}
}
internal sealed class JsonDocumentConverter
: JsonConverter<System.Text.Json.JsonDocument>
{
public override JsonDocument Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return JsonDocument.ParseValue(ref reader);
}
public override void Write(Utf8JsonWriter writer, JsonDocument value, JsonSerializerOptions options)
{
value.WriteTo(writer);
}
}
在 System.Text.Json 存在的情况下,我们不再能够使用以下 POST 操作:
[HttpPost]
public async Task<IActionResult> SubmitAsync(dynamic model)
相反,我们不得不使用以下方法,但在下游后端代码中没有直接使用“模型”的方法:
[HttpPost]
public async Task<IActionResult> SubmitAsync(JsonElement model)
“模型”是一个复杂对象,它可能包含一组对象和/或其他嵌套的复杂对象。 为了能够从JsonElement
得出dynamic
对象,我们必须调用 model.GetRawText() 并让 Newtonsoft 将其解码为动态对象。 这种方式不是理想的方式,因为本练习的主要目的是从项目中停用 Newtonsoft.json。
我可以假设解决此票证/问题意味着解决我们遇到的问题吗? 这似乎是一个急需解决的问题,所以它可以早点解决吗?
/cc @ahsonkhan @terrajobst
对 ExpandoObject 的 JsonSerializer 支持(临时措施)
我是新手,很多地方不完善,欢迎大家修改
.net Core3 不支持
添加使用:
```C#
///
/// 温度动态转换器
/// 作者:[email protected]
///
公共类 DynamicJsonConverter : JsonConverter
{
公共覆盖动态读取(参考 Utf8JsonReader 阅读器,
类型类型转换,
JsonSerializerOptions 选项)
{
if (reader.TokenType == JsonTokenType.True)
{
return true;
}
if (reader.TokenType == JsonTokenType.False)
{
return false;
}
if (reader.TokenType == JsonTokenType.Number)
{
if (reader.TryGetInt64(out long l))
{
return l;
}
return reader.GetDouble();
}
if (reader.TokenType == JsonTokenType.String)
{
if (reader.TryGetDateTime(out DateTime datetime))
{
return datetime;
}
return reader.GetString();
}
if (reader.TokenType == JsonTokenType.StartObject)
{
using JsonDocument documentV = JsonDocument.ParseValue(ref reader);
return ReadObject(documentV.RootElement);
}
// Use JsonElement as fallback.
// Newtonsoft uses JArray or JObject.
JsonDocument document = JsonDocument.ParseValue(ref reader);
return document.RootElement.Clone();
}
private object ReadObject(JsonElement jsonElement)
{
IDictionary<string, object> expandoObject = new ExpandoObject();
foreach (var obj in jsonElement.EnumerateObject())
{
var k = obj.Name;
var value = ReadValue(obj.Value);
expandoObject[k] = value;
}
return expandoObject;
}
private object? ReadValue(JsonElement jsonElement)
{
object? result = null;
switch (jsonElement.ValueKind)
{
case JsonValueKind.Object:
result = ReadObject(jsonElement);
break;
case JsonValueKind.Array:
result = ReadList(jsonElement);
break;
case JsonValueKind.String:
//TODO: Missing Datetime&Bytes Convert
result = jsonElement.GetString();
break;
case JsonValueKind.Number:
//TODO: more num type
result = 0;
if (jsonElement.TryGetInt64(out long l))
{
result = l;
}
break;
case JsonValueKind.True:
result = true;
break;
case JsonValueKind.False:
result = false;
break;
case JsonValueKind.Undefined:
case JsonValueKind.Null:
result = null;
break;
default:
throw new ArgumentOutOfRangeException();
}
return result;
}
private object? ReadList(JsonElement jsonElement)
{
IList<object?> list = new List<object?>();
foreach (var item in jsonElement.EnumerateArray())
{
list.Add(ReadValue(item));
}
return list.Count == 0 ? null : list;
}
public override void Write(Utf8JsonWriter writer,
object value,
JsonSerializerOptions options)
{
// writer.WriteStringValue(value.ToString());
}
}
## How to Use?
```C#
var serializerOptions = new JsonSerializerOptions
{
Converters = { new DynamicJsonConverter() }
};
return JsonSerializer.Deserialize<dynamic>("{OK:"200"}", serializerOptions);
@tchivs ,您的解决方案对我
c#
var serializerOptions = new JsonSerializerOptions();
serializerOptions.Converters.Add(new DynamicJsonConverter());
return JsonSerializer.Deserialize<dynamic>("{OK:"200"}", serializerOptions);
尝试使用 JsonElement 类型:
public JsonElement MyProperty {get; set;}
@tchivs ,我对您的代码进行了一些修改 - 对其进行了修改,以便它使用动态生成的“投影”类型(具有来自基类型的属性子集),而不是 ExpandoObject。 我在此处发布了代码(在示例控制台项目中): EDennis.DynamicDeserialization 。
我将在更复杂的对象和各种场景下测试这种方法(例如,用于修补现有的全类型 EF Core 实体的动态对象的反序列化;测试用例的 json 对象和数组的反序列化)。 如果您觉得这很有用,或者您发现任何问题,请告诉我。
感谢社区解决方法。 令人惊讶的是,Microsoft 无法在合理的时间范围内推出此功能。 在没有某种动态对象的情况下使用 GraphQL 响应会导致大量冗长和丑陋的代码。 或者甚至只是检查是否存在深度嵌套的属性。
我通读了评论线程,大多数都集中在反序列化上,我面临一个问题,即动态对象的序列化显然也“失败”了。 为了重现我的场景,我想出了以下最小重现:
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Text.Json;
namespace SampleConsoleApp
{
class Program
{
static void Main(string[] args)
{
dynamic d = new CustomDynamicObject();
d.AProperty = 10;
var s = JsonSerializer.Serialize(d);
Console.WriteLine(s);
Console.Read();
}
}
class CustomDynamicObject : DynamicObject
{
private readonly IDictionary<string, object> properties = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result) => properties.TryGetValue(binder.Name, out result);
public override bool TrySetMember(SetMemberBinder binder, object value)
{
properties[binder.Name] = value;
return true;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
foreach (var item in properties.Keys)
{
yield return item;
}
}
}
}
当运行s
为{}
,因此序列化不会失败但会产生一个空的 json 对象。
这是正确的问题吗? 或者我应该提高/跟随另一个?
这是正确的问题吗? 或者我应该提高/跟随另一个?
这是正确的问题。 无需为同一特征的两半打开一个。 这个问题是关于添加对 expando 对象的支持(这意味着对双方来说,序列化和反序列化)。
我今天遇到了这个问题 - 想说JsonElement
如果它不依赖于已处理的JsonDocument
会正常工作。 我能想到的解决这个问题的一种方法是为JsonDocument
实现一个析构函数,这样它的处理就可以推迟到以后的时间 - 一旦所有的JsonElement
对象都被收集起来。
我还需要一个动态对象。 但是,它还没有实施。 我的解决方案是使用字典。
JsonSerializer.Deserialize<Dictionary<string, string>>(response)
然后查找我需要的密钥:)
只是为了我自己的理智 - 问题是针对 5.0 的特定 ExpandoObject 支持还是反序列化为动态对象的能力? 这里的对话似乎并不完全与问题标题相匹配,我绝对需要后者。 就我而言,我正在反序列化嵌套动态,特别是List<Dictionary<string, dynamic>>
。 现在切换回 Newtonsoft :(
只是想分享一些@tchivs有用代码的 c# 8 语法糖模块 :)
/// <summary>
/// Temp Dynamic Converter with c# 8
/// by:[email protected]
/// </summary>
public class DynamicJsonConverter : JsonConverter<dynamic>
{
public override dynamic Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> reader.TokenType switch
{
JsonTokenType.True => true,
JsonTokenType.False => false,
JsonTokenType.Number => reader.TryGetInt64(out long l) ? 1 : reader.GetDouble(),
JsonTokenType.String => reader.TryGetDateTime(out DateTime datetime) ? datetime.ToString() : reader.GetString(),
JsonTokenType.StartObject => ReadObject(JsonDocument.ParseValue(ref reader).RootElement),
// Use JsonElement as fallback.
_ =>JsonDocument.ParseValue(ref reader).RootElement.Clone()
};
private object ReadObject(JsonElement jsonElement)
{
IDictionary<string, object> expandoObject = new ExpandoObject();
foreach (var obj in jsonElement.EnumerateObject())
{
var k = obj.Name;
var value = ReadValue(obj.Value);
expandoObject[k] = value;
}
return expandoObject;
}
private object? ReadValue(JsonElement jsonElement)
=>
jsonElement.ValueKind switch
{
JsonValueKind.Object => ReadObject(jsonElement),
JsonValueKind.Array => ReadList(jsonElement),
JsonValueKind.String => jsonElement.GetString(),
JsonValueKind.Number => jsonElement.TryGetInt64(out long l) ? 1 :0,
JsonValueKind.True => true,
JsonValueKind.False =>false,
JsonValueKind.Undefined => null,
JsonValueKind.Null => null,
_ => throw new ArgumentOutOfRangeException()
};
private object? ReadList(JsonElement jsonElement)
{
var list = new List<object?>();
jsonElement.EnumerateArray().ToList().ForEach(j => list.Add(ReadValue(j)));
return list.Count == 0 ? null : list;
}
public override void Write(Utf8JsonWriter writer,
object value,
JsonSerializerOptions options)
{
// writer.WriteStringValue(value.ToString());
}
}
@rs38感谢这里的代码,这正是我所需要的。 想要指出需要的一个非常微妙但重要的变化。 解析“数字”类型的两行在您的压缩版本中不正确:
JsonTokenType.Number => reader.TryGetInt64(out long l) ? 1 : reader.GetDouble(),
应该
JsonTokenType.Number => reader.TryGetInt64(out long l) ? l : reader.GetDouble(),
JsonValueKind.Number => jsonElement.TryGetInt64(out long l) ? 1 :0,
应该
JsonValueKind.Number => jsonElement.TryGetInt64(out long l) ? l :0,
@layomia这并不严重。 早就应该提供支持(事实上,我认为 System.Text.Json 不应该在没有它的情况下启动)! 而且我们甚至没有截止日期!
我的场景是关于 CosmosDB。 我正在使用使用此 JsonSerializer 的新 .NET SDK 进行查询,并且由于它是一个无模式数据库,因此我不想为我需要执行的数据库数据的每个投影创建一个类(有一堆不同的查询) .
我需要查询结果作为动态对象列表。
@SocVi100不要把你的希望寄托在微软@layomia燃起了对近期整合的所有希望。 他们似乎并不真正关心开发人员的需求。 首先,他们大喊“忘记 json.net,我们为您服务!” 幸运的是,开发人员没有忘记 json.net 或类似的东西。
你为什么不贡献? 实施它并提交 PR!
https://github.com/dotnet/runtime/blob/master/docs/coding-guidelines/adding-api-guidelines.md
https://github.com/dotnet/runtime/blob/master/docs/area-owners.md (领导:
@ericstj |,业主: @layomia @steveharter @jozkee)
你为什么不贡献? 实施它并提交 PR!
我希望我能够。
我的场景是关于 CosmosDB。 我正在使用使用此 JsonSerializer 的新 .NET SDK 进行查询,并且由于它是一个无模式数据库,因此我不想为我需要执行的数据库数据的每个投影创建一个类(有一堆不同的查询) .
我需要查询结果作为动态对象列表。
可以使用CosmosClientBuilder.WithCustomSerializer配置不同的序列化
这是一个例子: CosmosJsonNetSerializer
我们无法将此功能放入 5.0。 我们必须优先考虑 5.0 功能的其余部分工作,而这个不适合。 FWIW这非常接近切割线,因此后期移动。
@layomia燃起了对近期整合的所有希望。 他们似乎并不真正关心开发人员的需求。 首先,他们大喊“忘记 json.net,我们为您服务!” 幸运的是,开发人员没有忘记 json.net 或类似的东西。
@RobbyDeLaet我们可以试着保持这个讨论的建设性吗? 我们正在努力在保持设计原则的同时,尽最大努力响应客户要求最高的功能。 关于与 Newtonsoft.Json 的功能对等,这就是我们要说的。
System.Text.Json 主要关注性能、安全性和标准合规性。 对于某些场景,System.Text.Json 没有内置功能,但有推荐的解决方法。 如果您的应用程序依赖于缺失的功能,请考虑提交问题以了解是否可以添加对您的场景的支持。
我们的目标不是取代 Newtonsoft.JSON。 如果它对您有用,请继续使用它。 我们将尽最大努力使 System.Text.Json 尽可能有用,同时保持我们在性能、安全性、标准合规性和分层方面取得的成果。 随着时间的推移,我们希望让它为尽可能多的人服务。 我听到了这里的兴趣,并将确保我们专注于向前推进。
感谢您的建议。 我终于走到了中间,只使用 Newtonsoft 序列化器进行反序列化,但我仍然需要测试。 我希望在 CosmosDB 的默认序列化程序上获得 ExpandoObject 支持不会持续太久,这样我就可以摆脱旧的序列化程序。
@RobbyDeLaet ,感谢您的评论! 我对 Microsoft 实施 anyting 没有太多期望,我对它们感到沮丧太多次。 作为一名自由开发人员,我已经等了很多年了,实际上,为了在 CosmosDB、EntityFramework 和 Identity 基础设施上实现基本功能,他们以自己的方式无视我们。 他们在 UserVoice 或其他任何东西上有多少票并不重要。 我认为它自己的开发不需要这些功能,所以超出了范围......
问题总是一样的:太多的营销=太多的期望
为了帮助那些需要此功能的人,请参阅上面的代码示例以帮助解除阻止:
ExpandoObject
,集合使用List<object>
)ExpandoObject
)为了帮助满足此功能的要求,我将提供一个新的自定义转换器示例,并在准备就绪后将其链接到此处。 之后,我会将该示例添加到Newtonsoft 解决方法部分。 抄送@tdykstra
一个尚未讨论的细节是支持dynamic
需要对非常大的System.Linq.Expressions.dll
程序集的引用; 这种复杂性可能意味着将来我们在新程序集中添加动态转换器(例如System.Text.Json.Converters.dll
),以便为那些关心部署大小的人(例如独立的应用程序或 Blazor客户端应用程序)。
只是为了我自己的理智 - 问题是针对 5.0 的特定 ExpandoObject 支持还是反序列化为动态对象的能力? 这里的对话似乎并不完全与问题标题相匹配,我绝对需要后者。 就我而言,我正在反序列化嵌套动态,特别是
List<Dictionary<string, dynamic>>
。 现在切换回 Newtonsoft :(
我现在正在测试我为反序列化嵌套对象而实现的旧函数,并看到本主题中使用“valueKind”指出的相同问题。
有没有办法使用新的 neetonsoft.json 包来解决这个问题? 因为上面的代码适用于根级对象,但不适用于嵌套对象。
@ericstj抱歉,我的反应可能有点过于消极和苛刻,但就像@SocVi100 一样,我是一名自由开发人员,有时沮丧会占上风。 但至少我们在这里开始了讨论。 感谢您的回复,现在我们至少得到了有关此请求状态的明确消息。
只是为了我自己的理智 - 是针对 5.0 的问题专门针对 ExpandoObject 支持还是反序列化为动态对象的能力
我假设所需的语义是具有动态类型,因此在反序列化后,您可以以后期绑定的方式访问所有属性(包括嵌套):
dynamic obj = JsonSerializer.Deserialize<dynamic>(json);
string s = obj.MyChildProperty.MyStringList[2];
我假设所需的语义也明确支持ExpandoObject
:
ExpandoObject expando = JsonSerializer.Deserialize<ExpandoObject>(json);
dynamic obj = expando;
string s = obj.MyChildProperty.MyStringList[2];
所以我对范围的理解:
Deserialize<dynamic>(json)
返回原始值、集合或对象。 此处的对象可能是ExpandoObject
但也可能是IDynamicMetaObjectProvider
或 JITed 类型,具体取决于实现。 这与今天总是返回JsonElement
。Deserialize<ExpandoObject>(json)
(实现IDynamicMetaObjectProvider
)应该创建一个正确的ExpandoObject
,它又可以与dynamic
。 这与今天不同,它只为根属性创建扩展属性,并为所有嵌套属性创建JsonElement
实例。Serialize<ExpandoObect>()
按预期工作Serialize<IDynamicMetaObjectProvider
()>可能实现也可能不实现,取决于是否存在不使用ExpandoObject
场景。3.0 - 5.0 中的语义:
ExpandoObject
有效的,因为ExpandoObject
实现了IDictionary<string, object>
并且 STJ 将正确序列化每个object
值,无论它是原始值、集合还是对象。ExpandoObject
类型的作品,但只有根属性是“正确的”扩展属性; 任何嵌套属性都将是JsonElement
因此编程模型中存在不一致,因此除非使用自定义转换器,否则应避免反序列化ExpandoObject
。3.0-5.0 的选项:
ExpandoObject
和\或object
编写自定义转换器; 我将很快提供一个链接,指向一个理想地映射到 6.0 功能的新示例。ExpandoObject
(或dynamic
如果类型是基于ExpandoObject
)。 由于今天在 STJ 中反序列化ExpandoObject
存在不一致问题,因此不建议反序列化ExpandoObject
。JsonElement
代替动态对象。 JsonElement
不会尝试“猜测”JSON 映射到的类型,因此您必须通过调用 GetString()、GetInt32() 等来明确表示。此外,根据实现,自定义转换器的实现可能意味着在反序列化期间对 JSON 映射到的 CLR 类型存在一些“猜测”。 例如,JSON 字符串可能映射到DateTime
或string
,JSON 数字可能映射到double
或long
,以及需要确定 JSON 数组类型。 这需要与 Newtonsoft 语义进行审查和比较。 这也应该与当属性为object
类型时返回的类型一致(今天它是JsonElement
)。
以下是 3.0 - 5.0 STJ 语义的一些示例:
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Diagnostics;
using System.Linq;
using System.Text.Json;
namespace ConsoleApp
{
class Program
{
const string ExpectedJson = "{\"A\":\"A\",\"B\":[1,2],\"C\":42,\"D\":\"2020-01-01T00:00:00\",\"E\":{\"A_Child\":\"A_Child\"}}";
static void Main(string[] args)
{
DateTime dateTime = new DateTime(2020, 1, 1);
dynamic myDynamicChild = new ExpandoObject();
myDynamicChild.A_Child = "A_Child";
dynamic myDynamic = new ExpandoObject();
myDynamic.A = "A";
myDynamic.B = new List<int>() { 1, 2 };
myDynamic.C = 42;
myDynamic.D = dateTime;
myDynamic.E = myDynamicChild;
// Verify we can call late-bound property.
int c = myDynamic.C;
Debug.Assert(c == 42);
// STJ can serialize with ExpandoObject since it implements IDictionary<string, object>.
string json = JsonSerializer.Serialize<ExpandoObject>(myDynamic);
Debug.Assert(json == ExpectedJson);
// Using 'dynamic' against backing ExpandoObject works.
json = JsonSerializer.Serialize<dynamic>(myDynamic);
Debug.Assert(json == ExpectedJson);
// Deserialize with <dynamic>, <object> and <JsonElement>.
// For 5.0, using one of these is recommended over ExpandoObject because the programming model will be
// consistent for the root type and all nested types.
// Using <JsonElement> makes it clear and non-abiguous.
// Using <object> by default uses 'JsonElement', but can be overridden by a custom converter.
// Using <dynamic> uses 'object' which uses 'JsonElement'.
{
dynamic d = JsonSerializer.Deserialize<dynamic>(json);
VerifyJsonElement(d);
try
{
// We will get an exception here if we try to access a dynamic property since 'object' is deserialized
// as a JsonElement and not an ExpandoObject.
c = d.C;
Debug.Fail("Should have thrown Exception!");
}
catch (Exception ex)
{
Debug.Assert(ex.Message == "'System.Text.Json.JsonElement' does not contain a definition for 'C'");
}
// Serializing with <object> creates a JsonElement by default (can be changed by a custom converter).
object o = JsonSerializer.Deserialize<object>(json);
VerifyJsonElement((JsonElement)o);
// Serialize with explicit <JsonElement>.
JsonElement e = JsonSerializer.Deserialize<JsonElement>(json);
VerifyJsonElement(e);
}
// Deserialize with ExpandoObject. This creates an ExpandoObject with the root Type having Expando-properties
// but the value of those properties will be JsonElement. All other nested properties\objects\collections will
// also be JsonElement. Due to the inconsistency of having only root-level Expando-properties (such as A_Child),
// deserializing as ExpandoObject is not recommended (unless a ExpandoObject custom converter is used).
{
// When STJ deserializes, it creates ExpandoObjects via IDictionary<string, object> where 'object' is JsonElement.
ExpandoObject expando = JsonSerializer.Deserialize<ExpandoObject>(json);
Debug.Assert(((IDictionary<string, object>)expando).Keys.Count == 5);
myDynamic = expando;
JsonElement jsonElement = myDynamic.A;
Debug.Assert(jsonElement.GetString() == "A");
jsonElement = myDynamic.B;
Debug.Assert(jsonElement.EnumerateArray().Count() == 2);
jsonElement = myDynamic.C;
Debug.Assert(jsonElement.GetInt32() == 42);
jsonElement = myDynamic.D;
Debug.Assert(jsonElement.GetDateTime() == dateTime);
jsonElement = myDynamic.E;
// Here we have an inconsistency. Nested object property must use JsonElement (not a dynamic property).
Debug.Assert(jsonElement.GetProperty("A_Child").GetString() == "A_Child");
// Re-serialize works as expected.
json = JsonSerializer.Serialize<ExpandoObject>(myDynamic);
Debug.Assert(json == ExpectedJson);
// Re-serialize works as expected; dynamic works here since backed by ExpandoObject in this example.
json = JsonSerializer.Serialize<dynamic>(myDynamic);
Debug.Assert(json == ExpectedJson);
}
void VerifyJsonElement(JsonElement elem)
{
// Verify JsonElement
Debug.Assert(elem.GetProperty("A").GetString() == "A");
Debug.Assert(elem.GetProperty("B").EnumerateArray().Count() == 2);
Debug.Assert(elem.GetProperty("C").GetInt32() == 42);
Debug.Assert(elem.GetProperty("D").GetDateTime() == dateTime);
Debug.Assert(elem.GetProperty("E").GetProperty("A_Child").GetString() == "A_Child");
// Re-serialize
json = JsonSerializer.Serialize<dynamic>(elem);
Debug.Assert(json == ExpectedJson);
json = JsonSerializer.Serialize<JsonElement>(elem);
Debug.Assert(json == ExpectedJson);
}
}
}
}
@rs38你能根据 @ryan-hollister-q2 指出的内容修复你的代码片段吗?
正如所承诺的,提供动态实现示例的 PR 位于https://github.com/dotnet/runtime/pull/42097。
@rs38你能根据 @ryan-hollister-q2 指出的内容修复你的代码片段吗?
那不是我的代码,只是在此线程的前面分享了来自@tchivs 的一些片段。
最有用的评论
我也有一个用例 - 我只想使用 HttpClient 调用 REST API 并从响应中检索单个属性。 我不想创建一个专门的类来解析响应......使用 JSON.NET 我可以只使用“动态”并访问选择的属性。