Json.NET 没有使用属性将自定义 JsonConverter 应用到诸如 string [][] 之类的交错数组的项目的功能。 ItemConverterType 仅适用于最外层数组的项。
您可以做的是应用decorator pattern 来创建一个custom JsonConverter,该custom JsonConverter 为任意深度的锯齿状数组的最内部项目包装了一些内部项目转换器。
首先,定义如下转换器:
public class JaggedArrayItemConverterDecorator : JsonConverter
{
readonly JsonConverter itemConverter;
public JaggedArrayItemConverterDecorator(Type type) =>
itemConverter = (JsonConverter)Activator.CreateInstance(type ?? throw new ArgumentNullException());
public override bool CanConvert(Type objectType) => objectType.IsJaggedRankOneArray(out var itemType) && itemConverter.CanConvert(itemType);
public override bool CanRead => itemConverter.CanRead;
public override bool CanWrite => itemConverter.CanWrite;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
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 itemType = objectType.GetElementType();
IList list = (IList)serializer.ContractResolver.ResolveContract(typeof(List<>).MakeGenericType(itemType)).DefaultCreator();
while (reader.ReadToContentAndAssert().TokenType != JsonToken.EndArray)
{
if (itemType.IsArray)
list.Add(ReadJson(reader, itemType, null, serializer));
else
list.Add(itemConverter.ReadJson(reader, itemType, null, serializer));
}
var array = Array.CreateInstance(itemType, list.Count);
list.CopyTo(array, 0);
return array;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var itemType = value.GetType().GetElementType();
writer.WriteStartArray();
foreach (var item in (IList)value)
{
if (item == null)
writer.WriteNull();
else if (itemType.IsArray)
WriteJson(writer, item, serializer);
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 bool IsJaggedRankOneArray(this Type type, out Type innermostItemType)
{
innermostItemType = null;
var currentType = type ?? throw new ArgumentNullException(nameof(type));
while (currentType.IsArray)
{
if (currentType.GetArrayRank() != 1)
return false;
currentType = currentType.GetElementType();
}
if (currentType != type)
{
innermostItemType = currentType;
return true;
}
return false;
}
}
然后您可以将其应用于模型中任意深度的锯齿状数组,如下所示:
public class Model
{
[JsonProperty(ItemConverterType=typeof(InternedString))] // For 1d arrays you can use either ItemConverterType=typeof(InternedString) or JaggedArrayItemConverterDecorator
public string[] prizeTypes { get; set; }
[JsonConverter(typeof(JaggedArrayItemConverterDecorator), typeof(InternedString))]
public string[] prizeTypesByRoomType { get; set; }
[JsonConverter(typeof(JaggedArrayItemConverterDecorator), typeof(InternedString))]
public string[][] prizeTypesByRoomType2d { get; set; }
[JsonConverter(typeof(JaggedArrayItemConverterDecorator), typeof(InternedString))]
public string[][][] prizeTypesByRoomType3d { get; set; }
[JsonConverter(typeof(JaggedArrayItemConverterDecorator), typeof(InternedString))]
public string[][][][] prizeTypesByRoomType4d { get; set; }
[JsonProperty(ItemConverterType=typeof(InternedString))] // ItemConverterType works for multidimensional arrays
public string[,] prizeTypesMultidimensional { get; set; }
}
注意事项:
演示小提琴here.