C# 如何将自定义JsonConverter应用于字典中列表中的值?
我有一个用于整数的C# 如何将自定义JsonConverter应用于字典中列表中的值?,c#,json,json.net,jsonconverter,C#,Json,Json.net,Jsonconverter,我有一个用于整数的CustomConverter:JsonConverter,我需要向字典属性添加一个[JsonConverter(typeof(CustomConverter))]属性。将自定义转换器应用于int、列表或字典工作正常: public class Example { [JsonConverter(typeof(CustomConverter))] public int ExampleInt { get; set; } [JsonProperty(Item
CustomConverter:JsonConverter
,我需要向字典
属性添加一个[JsonConverter(typeof(CustomConverter))]
属性。将自定义转换器应用于int
、列表
或字典
工作正常:
public class Example
{
[JsonConverter(typeof(CustomConverter))]
public int ExampleInt { get; set; }
[JsonProperty(ItemConverterType = typeof(CustomConverter))]
public List<int> ExampleList { get; set; }
// How do I specify the Converter attribute for the int in the following line?
public Dictionary<string, List<int>> ExampleDictionary { get; set; }
}
公共类示例
{
[JsonConverter(类型(自定义转换器))]
public int ExampleInt{get;set;}
[JsonProperty(ItemConverterType=typeof(CustomConverter))]
公共列表示例列表{get;set;}
//如何在下一行中为int指定Converter属性?
公共字典示例字典{get;set;}
}
但是,我不知道如何指定CustomConverter应用于
字典
中列表
中的int
值。如何实现此功能?要实现此功能,需要创建CustomClass并继承它IDictionary
public class CustomClass : IDictionary<string, List<int>>
公共类CustomClass:IDictionary
然后,您可以使用类似以下内容的类:
public class Example {
[JsonConverter(typeof(CustomConverter)]
public string ExampleString { get; set; }
[JsonProperty(ItemConverterType = typeof(CustomConverter))]
public List<int> ExampleList { get; set; }
[JsonProperty(ItemConverterType = typeof(CustomConverter))]
public CustomClass data { get; set; }
}
公共类示例{
[JsonConverter(类型(自定义转换器)]
公共字符串示例字符串{get;set;}
[JsonProperty(ItemConverterType=typeof(CustomConverter))]
公共列表示例列表{get;set;}
[JsonProperty(ItemConverterType=typeof(CustomConverter))]
公共CustomClass数据{get;set;}
}
请告诉我您需要任何其他信息。Dictionary
是集合的嵌套集合,您正在查找类似于的ItemOfItemsConverterType
,以指定集合项的项的转换器。遗憾的是,没有实现此类属性。相反,它将需要为嵌套的列表
集合创建一个转换器,该集合调用所需的最里面的项转换器
这可以通过为列表
实现以下JsonConverter
来实现:
现在你应该准备好了。Demo fiddle。假设你的意思是
CustomClass:Dictionary
而不是CustomClass:IDictionary
,这似乎不起作用。Json.NET仍然尝试将CustomConverter
应用于字典的值,而不是字典的值。请查看哪一个应用失败Newtonsoft.Json.JsonSerializationException:转换器无法将指定值写入Json。需要System.Int32。
。即使使用CustomClass:IDictionary
,结果也应相同。Json.NET处理所有字典-无论是从字典继承还是仅在t中实现IDictionary
他也是这样。谢谢你的详细解释,效果很好!
public class ListItemConverterDecorator : JsonConverter
{
readonly JsonConverter itemConverter;
public ListItemConverterDecorator(Type type) =>
itemConverter = (JsonConverter)Activator.CreateInstance(type ?? throw new ArgumentNullException());
public override bool CanConvert(Type objectType) =>
!objectType.IsPrimitive && objectType != typeof(string) && objectType.BaseTypesAndSelf().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(List<>));
public override bool CanRead => itemConverter.CanRead;
public override bool CanWrite => itemConverter.CanWrite;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var itemType = objectType.BaseTypesAndSelf().Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(List<>)).Select(t => t.GetGenericArguments()[0]).First();
if (reader.MoveToContentAndAssert().TokenType == JsonToken.Null)
return null;
if (reader.TokenType != JsonToken.StartArray)
throw new JsonSerializationException(string.Format("Unexpected token {0}, expected {1}", reader.TokenType, JsonToken.StartArray));
var list = existingValue as IList ?? (IList)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
while (reader.ReadToContentAndAssert().TokenType != JsonToken.EndArray)
list.Add(itemConverter.ReadJson(reader, itemType, null, serializer));
return list;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteStartArray();
foreach (var item in (IList)value)
if (item == null)
writer.WriteNull();
else
itemConverter.WriteJson(writer, item, serializer);
writer.WriteEndArray();
}
}
public static partial class JsonExtensions
{
public static JsonReader ReadToContentAndAssert(this JsonReader reader) =>
reader.ReadAndAssert().MoveToContentAndAssert();
public static JsonReader MoveToContentAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (reader.TokenType == JsonToken.None) // Skip past beginning of stream.
reader.ReadAndAssert();
while (reader.TokenType == JsonToken.Comment) // Skip past comments.
reader.ReadAndAssert();
return reader;
}
public static JsonReader ReadAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (!reader.Read())
throw new JsonReaderException("Unexpected end of JSON stream.");
return reader;
}
}
public static class TypeExtensions
{
public static IEnumerable<Type> BaseTypesAndSelf(this Type type)
{
while (type != null)
{
yield return type;
type = type.BaseType;
}
}
}
public class Example
{
[JsonConverter(typeof(CustomConverter))]
public int ExampleInt { get; set; }
[JsonProperty(ItemConverterType = typeof(CustomConverter))]
public List<int> ExampleList { get; set; }
[JsonProperty(ItemConverterType = typeof(ListItemConverterDecorator),
ItemConverterParameters = new object [] { typeof(CustomConverter) })]
public Dictionary<string, List<int>> ExampleDictionary { get; set; }
}