c# - 将成员序列化为 Object 或 List<Object>

标签 c# json.net

这有点类似于JSON.net - field is either string or List

假设我有下面的 POCO 类,并且需要将 json 字符串反序列化为该类型。

public class Movie 
{
    [JsonProperty("title")]
    public List<string> Title { get; set; }

    [JsonProperty("images")]
    public List<Image> Images { get; set; }

    [JsonProperty("actors")]
    public List<Actor> Actors { get; set; }

    [JsonProperty("directors")]
    public List<Director> Directors { get; set; }    
}

假设需要反序列化的json字符串如下

{
    "title": "Movie title",
    "images": [ 
                {"url" : "http://www.url.com/img_3.jpg"},
                {"url" : "http://www.url.com/img_4.jpg"}
              ],
    "actors": [ 
                {"name" : "Steven Berkoff"},
                {"name" : "Nikolaj Coster-Waldau"},
                {"name" : "Julie Cox"}
              ],
    "directors": { "name" : "Simon Aeby" }
},
{  
    "title": "Movie title",
    "images": {"url" : "http://www.url.com/img_3.jpg"},                  
    "actors": {"name" : "Julie Cox"},                 
    "directors": { "name" : "Simon Aeby" }
}

这里的问题是,即使 POCO 需要导演、 Actor 和图像的列表,json 也只有每种类型之一。尝试反序列化时会出错。

最佳答案

为这些列表创建一个转换器,它可以识别列表中是否有一个或多个项目并将其应用到您的属性:

public class SingleOrEnumerableJsonConverter<TEnumerable> : JsonConverter
        where TEnumerable : IEnumerable
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(TEnumerable).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var obj = serializer.Deserialize<JToken>(reader);
        return ConvertObject(obj) ?? GetDefaultValue();
    }

    private object GetDefaultValue()
    {
        return Activator.CreateInstance<TEnumerable>();
    }

    private object ConvertObject(JToken obj)
    {
        try
        {
            return obj.ToObject<TEnumerable>();
        }
        catch (JsonSerializationException)
        {
            // try as an array of object
            return new JArray { obj }.ToObject<TEnumerable>();
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        object serializableValue = GetSerializableValue((TEnumerable)value, serializer);
        serializer.Serialize(writer, serializableValue);
    }

    private object GetSerializableValue(TEnumerable items, JsonSerializer serializer)
    {
        var arr = new JArray(items.Cast<object>()
            .Select(item => JToken.FromObject(item, serializer))
        );
        return arr.Count > 1 ? arr : arr.SingleOrDefault();
    }
}
public class Movie 
{
    [JsonProperty("title")]
    [JsonConverter(typeof(SingleOrEnumerableJsonConverter<List<string>>))]
    public List<string> Title { get; set; }

    [JsonProperty("images")]
    [JsonConverter(typeof(SingleOrEnumerableJsonConverter<List<Image>>))]
    public List<Image> Images { get; set; }

    [JsonProperty("actors")]
    [JsonConverter(typeof(SingleOrEnumerableJsonConverter<List<Actor>>))]
    public List<Actor> Actors { get; set; }

    [JsonProperty("directors")]
    [JsonConverter(typeof(SingleOrEnumerableJsonConverter<List<Director>>))]
    public List<Director> Directors { get; set; }    
}

关于c# - 将成员序列化为 Object 或 List<Object>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21301805/

相关文章:

c# - 使用枚举数组反序列化 json

c# - EFCore 删除引用的实体

c# - 使用 UpdateProgress 的问题

c# - Json.NET 问题

c# - JSonConverter 如何进行泛型反序列化

asp.net-mvc - 在 MVC4 中使用 JsonConvert.SerializeObject 清理输入?

c# - 为什么 .NET 对象有方法 Finalize()?

c# - 字符串文字和内存表示

c# - 如何确定服务器端 C# 上的浏览​​器窗口大小

c# - WebApi 响应反序列化为 List<string>