有两个班
public class Playlist {
public string Name { get; set; }
public Schedule Schedule1 { get; set; }
public Schedule Schedule2 { get; set; }
}
public interface Schedule {
string Name { get; set; }
}
[JsonObject(MemberSerialization = MemberSerialization.OptIn, IsReference = true)]
public class ScheduleImpl : Schedule {
[JsonProperty]
public string Name { get; set; }
}
每个播放列表有两个时间表,客户端代码如下,
static void Main(string[] args) {
Playlist p1 = new Playlist { Name = "playlist1" };
p1.Schedule1 = new ScheduleImpl { Name = "schedule1" };
p1.Schedule2 = p1.Schedule1;
var content = Serialize(p1);
Console.WriteLine(content);
Console.WriteLine("----------------------------------------------------");
Console.ReadLine();
var p = Deserialize<Playlist>(content);
Console.WriteLine(p.Schedule1.Name);
Console.WriteLine(p.Schedule2.Name);
Console.WriteLine("press any key to exit.");
Console.ReadLine();
}
private static string Serialize(Playlist arg) {
var settings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore };
return JsonConvert.SerializeObject(arg, Formatting.Indented, settings);
}
private static T Deserialize<T>(string arg) {
var settings = new JsonSerializerSettings();
settings.Converters = new JsonConverter[] {
new CustomCreationConverter<Schedule, ScheduleImpl>()
};
return JsonConvert.DeserializeObject<T>(arg, settings);
}
自定义创建转换器无法处理引用,我应该自己解析“引用”吗?
public class CustomCreationConverter<A, T> : CustomCreationConverter<A>
where T : A, new() {
public override A Create(Type objectType) {
return new T();
}
}
json输出是,
{ “名称”:“播放列表1”, “时间表1”:{ "$id": "1", “名称”:“计划 1” }, “时间表2”:{ "$ref": "1" } }
我从源代码中得到了答案,
public class InheritConverter<T> : JsonConverter {
public override bool CanConvert(Type objectType) {
return typeof(T).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
if (reader.TokenType == JsonToken.Null) return null;
JObject jObject = JObject.Load(reader);
T target = default(T);
if (jObject != null) {
if (jObject["$ref"] != null) {
string id = (jObject["$ref"] as JValue).Value as string;
target = (T)serializer.ReferenceResolver.ResolveReference(serializer, id);
} else {
target = Create(objectType, jObject);
serializer.Populate(jObject.CreateReader(), target);
}
}
return target;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
throw new InvalidOperationException("never use this in serialize");
}
protected virtual T Create(Type objectType, JObject jObject) {
T result = default(T);
try {
var type = (jObject["$type"] as JValue).Value as string;
result = (T)Activator.CreateInstance(Type.GetType(type));
} catch (NullReferenceException) {
throw new InvalidCastException("Add ItemTypeNameHandling setting");
}
return result;
}
}