8

有两个班

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;
    }
}
4

0 回答 0