这似乎是设计意图——与 NewtonsoftJavaScriptSerializer
和一样DataContractJsonSerializer
,字典键和值是序列化的,而不是常规属性。
作为扩展的替代方法Dictionary<TKey, TValue>
,您可以通过将字典封装在容器类中并使用以下标记来获取所需的 JSON JsonExtensionDataAttribute
:
internal class Translation
{
public string Name { get; set; }
[JsonExtensionData]
public Dictionary<string, object> Data { get; set; } = new Dictionary<string, object>();
}
然后序列化如下:
var translation = new Translation
{
Name = "donkey",
Data =
{
{"key1", "value1"},
{"key2", "value2"},
{"key3", "value3"},
},
};
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
// Other options as required
WriteIndented = true,
};
var json = JsonSerializer.Serialize(translation, options);
请注意文档中的此限制
字典的 TKey 值必须是String,而 TValue 必须是JsonElement或Object。
(顺便说一句,类似的方法适用于拥有自己的 .Newtonsoft 的方法JsonExtensionDataAttribute
。如果您同时使用这两个库,请确保不要混淆属性。)
演示小提琴#1在这里。
如果对您的数据模型的这种修改不方便,您可以引入一个自定义JsonConverter<Translation>
(反)序列化 DTO,如上面的模型,然后将 DTO 映射到您的最终模型:
internal class Translation : Dictionary<string, string>
{
public string Name { get; set; }
}
internal class TranslationConverter : JsonConverter<Translation>
{
internal class TranslationDTO
{
public string Name { get; set; }
[JsonExtensionData]
public Dictionary<string, object> Data { get; set; }
}
public override Translation Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var dto = JsonSerializer.Deserialize<TranslationDTO>(ref reader, options);
if (dto == null)
return null;
var translation = new Translation { Name = dto.Name };
foreach (var p in dto.Data)
translation.Add(p.Key, p.Value?.ToString());
return translation;
}
public override void Write(Utf8JsonWriter writer, Translation value, JsonSerializerOptions options)
{
var dto = new TranslationDTO { Name = value.Name, Data = value.ToDictionary(p => p.Key, p => (object)p.Value) };
JsonSerializer.Serialize(writer, dto, options);
}
}
然后序列化如下:
var translation = new Translation
{
Name = "donkey",
["key1"] = "value2",
["key2"] = "value2",
["key3"] = "value3",
};
var options = new JsonSerializerOptions
{
Converters = { new TranslationConverter() },
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
// Other options as required
WriteIndented = true,
};
var json = JsonSerializer.Serialize(translation, options);
我发现(反)序列化为 DTO 比直接使用更简单Utf8JsonReader
,Utf8JsonWriter
因为边缘情况和命名策略会自动处理。只有当性能至关重要时,我才会直接与读者和作者合作。
使用任何一种方法JsonNamingPolicy.CamelCase
都需要"name"
在 JSON 中绑定到Name
模型中。
演示小提琴#2在这里。