回答我自己的问题:
目前有两种解决方案。第一个是在 dbc 的评论中推荐的:简单地使用JsonPropertyAttribute.ItemConverterType
来告诉 Json 使用DefinitionJConverter
或ReferenceJConverter
在装饰集合的元素上。
仅仅因为这个解决方案与我当前的其他方法不一致,并且因为我更喜欢较短的属性名称,所以我还将展示我自己的解决方案:
创建另外两个名为DefCollectionJConverter
和的自定义转换器RefCollectionJConverter
。在合约解析器中,将这些附加到任何发现的包含用[Ref]
. 此外,如果集合本身已用 装饰[Def]
,则将其传递给DefCollectionJConverter
,如下所示:
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
// Do not handle properties (it's difficult to concieve of a time when properties should be serialised at all).
if(member is PropertyInfo)
{
return property;
}
else if(member is FieldInfo)
{
FieldInfo field = ((FieldInfo)member);
// Does this field implement IList? This Utility function gets all member interfaces and checks if any of them equal the argued interface.
if (field.FieldType.ImplementsInterface<IList>())
{
// Are the elements of this IList decorated with [Ref]?
if (field.FieldType.GetGenericArguments()[0].HasAttribute<RefAttribute>())
{
// Does this collection field have [Def]?
if (field.HasAttribute<DefAttribute>())
{
// This is a collection of definitions.
property.Converter = new DefCollectionJConverter();
}
else
{
// This is a collection of references.
property.Converter = new RefCollectionJConverter();
}
}
}
else
{
// If the field's type class has been decorated with Ref.
if (field.FieldType.HasAttribute<RefAttribute>())
{
if (member.HasAttribute<DefAttribute>())
{
// If this particular field also has Def, it's a definition.
property.Converter = new DefinitionJConverter();
}
else
{
// Else it's a reference.
property.Converter = new ReferenceJConverter();
}
}
}
}
return property;
}
在 Collection 转换器本身内部,填充 aJArray
然后调用JArray.WriteTo()
. JToken
使用定义的默认序列化程序或引用的自定义引用序列化程序构造s:
public class DefCollectionJConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JArray array = new JArray();
IList list = (IList)value;
if (list.Count > 0)
{
// Populate the JArray with JTokens from the list elements. Pass the current serializer, which should contain default settings and converters.
// This should handle child objects appropriately, too.
JsonSerializer defSerializer = new JsonSerializer();
defSerializer.Converters.Add(new DefinitionJConverter());
for (int e = 0; e < list.Count; e++)
{
JToken first = JToken.FromObject(list[e], serializer);
array.Add(first);
}
array.WriteTo(writer);
}
else
{
Debug.LogError("List was empty.");
}
}
}
public class RefCollectionJConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JArray array = new JArray();
IList list = (IList)value;
if(list.Count > 0)
{
// Populate the JArray with JTokens of the list elements, using a serialiser that only contains ReferenceJConverter.
// Note that we don't need to worry about this token's children: only definitions can describe children.
JsonSerializer refSerializer = new JsonSerializer();
refSerializer.Converters.Add(new ReferenceJConverter());
for(int e = 0; e < list.Count; e++)
{
JToken first = JToken.FromObject(list[e], refSerializer);
array.Add(first);
}
array.WriteTo(writer);
}
else
{
Debug.LogError("List was empty.");
}
}
}
对于这些转换器,我CanConvert()
总是返回 true,因为我是手动分配这些转换器的。
我还没有用反序列化测试过这个,但我不明白为什么它不起作用。