有两个班级
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);
}
自定义创建转换器无法处理引用,我应该自己解析'ref'吗?
public class CustomCreationConverter<A, T> : CustomCreationConverter<A>
where T : A, new() {
public override A Create(Type objectType) {
return new T();
}
}
,json输出为,
{ "Name": "playlist1", "Schedule1": { "$id": "1", "Name": "schedule1" }, "Schedule2": { "$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;
}
}