C# JSON.net-字段为字符串或列表<;字符串>;

C# JSON.net-字段为字符串或列表<;字符串>;,c#,windows-phone-7,json.net,C#,Windows Phone 7,Json.net,我遇到过这样一种情况,从REST-服务返回的JSON返回一个电影对象列表,所有这些对象都包含大量信息。REST中的几个字段-服务结果根据可用信息而变化 例如:一部电影总是有一些屏幕截图(图像)、演员和导演。根据所讨论的电影,可能有一个或多个图像、一个或多个演员和一个或多个导演。几个案例的JSON示例: { "title": "Movie title", "images": [ "http://www.url.com/img_0.jpg", "htt

我遇到过这样一种情况,从
REST
-服务返回的
JSON
返回一个电影对象列表,所有这些对象都包含大量信息。
REST
中的几个字段-服务结果根据可用信息而变化

例如:一部电影总是有一些屏幕截图(图像)、演员和导演。根据所讨论的电影,可能有一个或多个图像、一个或多个演员和一个或多个导演。几个案例的JSON示例:

{
    "title": "Movie title",
    "images": [
        "http://www.url.com/img_0.jpg",
        "http://www.url.com/img_1.jpg",
        "http://www.url.com/img_2.jpg",
        "http://www.url.com/img_3.jpg",
        "http://www.url.com/img_4.jpg"
    ],
    "actors": [
        "Steven Berkoff",
        "Nikolaj Coster-Waldau",
        "Julie Cox"
    ],
    "directors": "Simon Aeby"
},
{
    "title": "Another movie",
    "images": "http://www.url.com/img_1.jpg",
    "actors": "actor 1"
    "directors": [
        "Justin Bieber",
        "Justin Timberlake"
    ]
}
问题是,使用JSON.net,我如何创建一个转换器来处理这个问题?我一直在网上搜寻,但仍然没有找到解决办法

关于同一问题的另一种说法是:如果字段是字符串列表或简单字符串,我如何让JSON.NET以任何方式创建列表(如果只是一个简单字符串,则创建一个包含一个成员的列表)


编辑:此REST服务不在我的控制范围内

您将无法直接序列化到对象,但您可以手动执行,无需太多工作。Net包含LINQ到JSON。首先定义一个方法,该方法将始终返回类型为T的列表,即使基础JSON不是数组:

public List<T> getSingleOrArray<T>(JToken token)
{
    if (token.HasValues)
    {
        return token.Select(m => m.ToObject<T>()).ToList();
    }
    else
    {
        return new List<T> { token.ToObject<T>() };
    }
}
public List getSingleOrArray(JToken令牌)
{
if(token.HasValues)
{
返回标记。选择(m=>m.ToObject()).ToList();
}
其他的
{
返回新列表{token.ToObject()};
}
}
示例用法:

JObject m1 = JObject.Parse(@"{
""title"": ""Movie title"",
""images"": [
    ""http://www.url.com/img_0.jpg"",
    ""http://www.url.com/img_1.jpg""
],
""actors"": [
    ""Steven Berkoff"",
    ""Julie Cox""
],
""directors"": ""Simon Aeby""
}");

JObject m2 = JObject.Parse(@"{
""title"": ""Another movie"",
""images"": ""http://www.url.com/img_1.jpg"",
""actors"": ""actor 1"",
""directors"": [
    ""Justin Bieber"",
    ""Justin Timberlake""
]
}");

IList<String> m1_directors = getSingleOrArray<string>(m1["directors"]);
IList<String> m2_directors = getSingleOrArray<string>(m2["directors"]);
JObject m1=JObject.Parse(@){
“片名”:“电影片名”,
“图像”:[
""http://www.url.com/img_0.jpg"",
""http://www.url.com/img_1.jpg""
],
“演员”:[
“Steven Berkoff”,
“朱莉·考克斯”
],
“董事”:“西蒙·艾比”
}");
JObject m2=JObject.Parse(@){
“标题”:“另一部电影”,
“图像”:http://www.url.com/img_1.jpg"",
“演员”:“演员1”,
“董事”:[
“贾斯汀·比伯”,
“贾斯汀·汀布莱克”
]
}");
IList m1_directors=getSingleOrray(m1[“directors”);
IList m2_directors=GetSingleOrray(m2[“directors”);
m1\u目录是一个包含单个元素的列表,m2\u控制器是一个包含两个元素的列表。

好的,我这样做是为了好玩,但无论如何,我认为这不是有用的或最好的方法

将“动态”属性声明为对象,然后创建方法以获取类似ImagesAsList或ImagesAsString的属性。我是用扩展方法做的

var movies = JsonConvert.DeserializeObject<List<Movie>>(str);
扩展方法

static class MovieExtension
{
    public static List<string> ImagesAsList(this Movie m)
    {
        var jArray = (m.Images as JArray);
        if (jArray == null) return null;

        return jArray.Select(x => x.ToString()).ToList();
    }

    public static string ImagesAsString(this Movie m)
    {
        return m.Images as string;
    }

}
静态类电影扩展
{
公共静态列表ImagesList(此电影m)
{
var jArray=(m.Images作为jArray);
if(jArray==null)返回null;
返回jArray.Select(x=>x.ToString()).ToList();
}
公共静态字符串ImagesString(此电影为m)
{
以字符串形式返回m.图像;
}
}

编辑

在阅读了@yamen评论之后,我做了一些改变,比如:

var settings = new JsonSerializerSettings();
settings.Converters.Add(new MoviesConverter());

var movies = JsonConvert.DeserializeObject<List<Movie>>(str, settings);
var settings=newjsonserializersettings();
settings.converter.Add(新的moviescoverter());
var movies=JsonConvert.DeserializeObject(str,settings);
阶级

类电影
{
[JsonProperty(“所有权”)]
公共列表标题{get;set;}
[JsonProperty(“图像”)]
公共列表图像{get;set;}
[JsonProperty(“参与者”)]
公共列表参与者{get;set;}
[JsonProperty(“董事”)]
公共列表控制器{get;set;}
}
转换器

class MoviesConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(string)) || (objectType == typeof(List<string>)) ;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartArray)
        {
            var l = new List<string>();
            reader.Read();
            while (reader.TokenType != JsonToken.EndArray)
            {
                l.Add(reader.Value as string);

                reader.Read();
            }
            return l;
        }
        else
        {
            return new List<string> { reader.Value as string };
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        //ToDo here we can decide to write the json as 
        //if only has one attribute output as string if it has more output as list
    }
}
class moviescoverter:JsonConverter
{
公共覆盖布尔CanConvert(类型objectType)
{
return(objectType==typeof(string))| |(objectType==typeof(List));
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
if(reader.TokenType==JsonToken.StartArray)
{
var l=新列表();
reader.Read();
while(reader.TokenType!=JsonToken.EndArray)
{
l、 添加(reader.Value作为字符串);
reader.Read();
}
返回l;
}
其他的
{
返回新列表{reader.Value as string};
}
}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
//在这里,我们可以决定将json编写为
//如果只有一个属性输出为字符串,如果它有多个输出为列表
}
}

这是您的服务还是第三方?我会建议编辑服务,如果可能的话。因为如果fileld不是json中的数组,则无法将其序列化为数组。或者,您可以对对象进行反序列化,然后将其映射到您的类更新了general post以使内容更清晰许多使用JS等脚本语言的API都会返回类似的结果。最常见的情况是返回为(单个字符串)的错误消息或返回为(字符串列表)的错误消息。因为它并不总是显示在文档中,所以需要对API进行许多查询才能得到这个问题。自定义JSON转换器应检查JSON中的属性类型并进行转换。在本例中,它是字符串列表。我认为不需要声明为对象。声明always as List(或List),当底层JSON不是数组时,只返回单个元素。这就是API的行为方式,因此用这种方式编写系统也是未来的证明。额外的好处是有一个明确的映射层。好的,做了一些更改并扩展了JSONConvert类。这个答案应该对yamen当前选择的答案非常有利。它很好地利用了JSON.NET的转换器,并且只要您正确地修饰对象,任何通用解析都仍然可以工作:)+1指针感谢,这大大有助于处理sendgrid在批处理事件api(“类别”)中提供的荒谬的“JSON”可以是一个字符串属性,也可以是一个字符串数组……不知道是谁梦到了这个宝石!)。因为我很懒,所以我一直在寻找答案。谢谢,但我想为其他人添加一条评论
class Movie
{

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

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

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

    [JsonProperty("directors")]
    public List<string> Directors { get; set; }
}
class MoviesConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(string)) || (objectType == typeof(List<string>)) ;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartArray)
        {
            var l = new List<string>();
            reader.Read();
            while (reader.TokenType != JsonToken.EndArray)
            {
                l.Add(reader.Value as string);

                reader.Read();
            }
            return l;
        }
        else
        {
            return new List<string> { reader.Value as string };
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        //ToDo here we can decide to write the json as 
        //if only has one attribute output as string if it has more output as list
    }
}