作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
是否可以使用 System.Text.Json 将字典序列化(和反序列化)为数组?
而不是 { "hello": "world" }
我需要将我的字典序列化为 { "key": "hello", "value": "world" }
最好不必在我的类的字典属性上设置属性。
使用 newtonsoft.json 可以这样:
class DictionaryAsArrayResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
if (objectType.GetInterfaces().Any(i => i == typeof(IDictionary) ||
(i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary<,>))))
{
return base.CreateArrayContract(objectType);
}
return base.CreateContract(objectType);
}
}
最佳答案
您可以使用 JsonConverterFactory
来执行此操作制造特定的 JsonConverter<T>
对于要序列化为数组的每种字典类型。这是一个适用于所有实现 IDictionary<TKey, TValue>
的类的转换器。 :
public class DictionaryConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
{
return typeToConvert.IsClass && typeToConvert.GetDictionaryKeyValueType() != null && typeToConvert.GetConstructor(Type.EmptyTypes) != null;
}
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
var keyValueTypes = typeToConvert.GetDictionaryKeyValueType();
var converterType = typeof(DictionaryAsArrayConverter<,,>).MakeGenericType(typeToConvert, keyValueTypes.Value.Key, keyValueTypes.Value.Value);
return (JsonConverter)Activator.CreateInstance(converterType);
}
}
public class DictionaryAsArrayConverter<TKey, TValue> : DictionaryAsArrayConverter<Dictionary<TKey, TValue>, TKey, TValue>
{
}
public class DictionaryAsArrayConverter<TDictionary, TKey, TValue> : JsonConverter<TDictionary> where TDictionary : class, IDictionary<TKey, TValue>, new()
{
struct KeyValueDTO
{
public TKey Key { get; set; }
public TValue Value { get; set; }
}
public override TDictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var list = JsonSerializer.Deserialize<List<KeyValueDTO>>(ref reader, options);
if (list == null)
return null;
var dictionary = typeToConvert == typeof(Dictionary<TKey, TValue>) ? (TDictionary)(object)new Dictionary<TKey, TValue>(list.Count) : new TDictionary();
foreach (var pair in list)
dictionary.Add(pair.Key, pair.Value);
return dictionary;
}
public override void Write(Utf8JsonWriter writer, TDictionary value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value.Select(p => new KeyValueDTO { Key = p.Key, Value = p.Value }), options);
}
}
public static class TypeExtensions
{
public static IEnumerable<Type> GetInterfacesAndSelf(this Type type)
{
if (type == null)
throw new ArgumentNullException();
if (type.IsInterface)
return new[] { type }.Concat(type.GetInterfaces());
else
return type.GetInterfaces();
}
public static KeyValuePair<Type, Type>? GetDictionaryKeyValueType(this Type type)
{
KeyValuePair<Type, Type>? types = null;
foreach (var pair in type.GetDictionaryKeyValueTypes())
{
if (types == null)
types = pair;
else
return null;
}
return types;
}
public static IEnumerable<KeyValuePair<Type, Type>> GetDictionaryKeyValueTypes(this Type type)
{
foreach (Type intType in type.GetInterfacesAndSelf())
{
if (intType.IsGenericType
&& intType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
{
var args = intType.GetGenericArguments();
if (args.Length == 2)
yield return new KeyValuePair<Type, Type>(args[0], args[1]);
}
}
}
}
JsonSerializerOptions.Converters
本地如下:
var options = new JsonSerializerOptions
{
Converters = { new DictionaryConverterFactory() },
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
var json = JsonSerializer.Serialize(dictionary, options);
var dictionary2 = JsonSerializer.Deserialize<TDictionary>(json, options);
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new DictionaryConverterFactory());
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
DictionaryAsArrayConverter<TKey, TValue>
如果您只想将某些字典类型序列化为数组,也可以直接使用。
JsonSerializer
目前不尊重 PropertyNamingPolicy
序列化时 KeyValuePair<TKey, TValue>
(见 Issue #1197 )所以我不得不介绍一个 KeyValueDTO
获取外壳"key"
和 "value"
根据您的问题的要求。 IDictionary
实现转换器类型。这可以作为答案的扩展来完成。 DefaultContractResolver
的类型在 System.Text.Json
-- JsonClassInfo
和 JsonPropertyInfo
-- 是 内部 .有一个开放的增强 Equivalent of DefaultContractResolver in System.Text.Json #42001要求公共(public)等价物。 关于c# - System.Text.Json 将字典序列化为数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59644016/
出于好奇,我尝试了一些原型(prototype)制作,但似乎只允许在第一个位置使用子例程的原型(prototype) &。 当我写作时 sub test (&$$) { do_somethin
我需要开发一个类似于 Android Play 商店应用程序或类似 this app 的应用程序.我阅读了很多教程,发现几乎每个教程都有与 this one 类似的例子。 . 我已经开始使用我的应用程
考虑一个表示“事件之间的时间”的列: (5, 40, 3, 6, 0, 9, 0, 4, 5, 18, 2, 4, 3, 2) 我想将这些分组到 30 个桶中,但桶会重置。期望的结果: (0, 1,
我是一名优秀的程序员,十分优秀!