如果对象位于序列化上下文的顶层,我希望能够完全序列化该对象,但是可以通过引用将上下文中较低的对象序列化。
我已经使用自定义合同解析器,自定义Json转换器和自定义IReferenceResolver搜索并尝试了测试,但找不到解决方法。
例如,想象一下一个IdType类,在顶层我想对其所有属性进行序列化,但是在属性,列表或字典中遇到这样的对象的引用时,我想产生一个引用。
对此类型进行测试
public class IdType
{
public IdType(string id)
{
Id = id;
}
public string Id {get;}
public string Name {get;set;}
public int Number {get; set;}
public IdType OtherType { get; set; }
public IEnumerable<IdType> Types { get; set;}
public IDictionary<IdType, string> { get; set; }
public IDictionary<string, IdType> {get; set; }
}
[TestMethod]
public void SerializeTest()
{
var t1 = new IdType(1) { Name = 'Alice', Number = 42 };
var t2 = new IdType(2) { Name = 'Bob', Number = 21, OtherType = t1 };
var t3 = new IdType(2) { Name = 'Charlie', Number = 84, OtherType = t2, Types = new[] {t1, t2} };
var testTypes = new[]
{
t1,
t3
};
var serializer = new JsonSerializer
{
Formatting = Formatting.Indented,
};
StringWriter writer;
using (writer = new StringWriter())
{
serializer.Serialize(writer, myObject);
}
Console.WriteLine(writer.ToString());
}
我想要这样的输出
[
{
"Id": "1",
"Name": "Alice"
"Number": 42,
},
{
"Id": "3",
"Name": "Charlie"
"Number": 84,
"OtherType": 2
"Types": [
"Id" : 1, 2
]
}
]
JsonConverter没有上下文,因此它将始终以一种方式或另一种方式进行转换。
自定义解析器(从DefaultContractResolver派生)将适用于IdType类型的属性,但我不知道如何使其与列表和词典一起使用。
最近我尝试使用PreserveReferenceHandling和具有顶级元素ID的自定义IReferenceResolver。但这不起作用,因为序列化是深度优先。
我们将很高兴收到任何实现此目标的建议
答案 0 :(得分:0)
我想我已经回答了我自己的问题。如果我结合使用了自定义合同解析器和自定义转换器,并有条件地将转换器添加到要序列化为ID的属性中,那么它似乎可以正常工作。
我还没有实现字典,但这适用于基本属性和列表:
public class CustomResolver : DefaultContractResolver
{
readonly CamelCasePropertyNamesContractResolver innerResolver = new CamelCasePropertyNamesContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var jsonProperty = base.CreateProperty(member, memberSerialization);
if (!jsonProperty.PropertyType.IsPrimitive && jsonProperty.PropertyType != typeof(string) && jsonProperty.Readable)
{
var innerContract = innerResolver.ResolveContract(jsonProperty.PropertyType);
if (typeof(IdType).IsAssignableFrom(innerContract.UnderlyingType) && innerContract is JsonObjectContract objectContract)
{
jsonProperty.Converter = new IdConverter();
}
else if (typeof(IEnumerable<IdType>).IsAssignableFrom(innerContract.UnderlyingType) && innerContract is JsonArrayContract arrayContract)
{
jsonProperty.Converter = new IdConverter();
}
}
return jsonProperty;
}
}
internal class IdConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (typeof(IdType).IsAssignableFrom(objectType) ||
typeof(IEnumerable<IdType>).IsAssignableFrom(objectType));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value is IdType item)
{
JToken token = JToken.FromObject(item.Id);
token.WriteTo(writer);
}
else if (value is IEnumerable<IdType> itemCollection)
{
JArray array = new JArray();
foreach (var i in itemCollection)
{
JToken token = JToken.FromObject(i.Id);
array.Add(token);
}
array.WriteTo(writer);
}
}
public override bool CanRead
{
get { return false; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
要序列化并使用自定义解析器,您将:
var serializer = new JsonSerializer
{
Formatting = Formatting.Indented,
ContractResolver = new CustomResolver(),
};