Как инициировать объект класса из словаря с помощью Lambda / LINQ, анализируемого Newtonsoft.Json?

#c# #linq #lambda #ffmpeg

#c# #linq #lambda #ffmpeg

Вопрос:

со вчерашнего дня я пытался реализовать ffmpeg через Xabe-Wrapper в моем C #-проекте. Я использовал FFMpeg => FFProbe для получения форматирования и потоковой передачи данных в виде json-строки из некоторых фильмов. Это json, который я получил для потоков.

 "{
  "streams": [
    {"codec_name": "mpeg4", "codec_type": "video"},
    {"codec_name": "mp3"  , "codec_type": "audio"}
  ]
}"
  

Следуя Newtonsoft Wiki, я десериализовал его как DataSet. Я начал играть и нашел способ сделать это в «oneliner».

Streams = (JsonConvert.DeserializeObject<DataSet>(StreamProbeJSON,
JSerializerSettings)).Tables["streams"].AsEnumerable().Select(value => new
FormatAVInfo.SInfo(value.Field<string>("codec_type"), value.Field<string>
("codec_name")));

Для формата я получаю этот Json

 {
    "format": {
        "format_name": "avi",
        "probe_score": 100
    }
}
  

Следуя Newtonsoft Wiki, я десериализовал этот объект как словарь, но я не в состоянии снова сделать это в oneliner. Это не большая проблема, но я хотел бы узнать, как я могу этого добиться?

Я попробовал это

 Format = (JsonConvert.DeserializeObject<Dictionary<string, 
    Dictionary<string, string>>>(FormatProbeJSON, JSerializerSettings)) 
    ["format"].Select(value => new FormatAVInfo.FInfo(value["format_name"], 
    value["probe_score"]));
  

Но, конечно, я получаю KeyValuePair и не могу использовать индексатор для этого. Я также пробовал с помощью JObject, с тем же результатом. Конечно, я мог бы просто создать другое поле

 Dictionary<string,string> Temp = 
    (JsonConvert.DeserializeObject<Dictionary<string, 
    Dictionary<string, string>>>(FormatProbeJSON, JSerializerSettings)) 
    ["format"]
  

И создать экземпляр впоследствии, но мне любопытно, есть ли способ сделать это.

Спасибо

Комментарии:

1. Почему вы не десериализуете его в реальную модель вместо словарей? Тогда это просто JsonConvert.DeserializeObject<MyModel>(json) это хорошая и короткая строка.

2. Я немного аутист, и мне не нравятся имена полей, которые я не могу переименовать. Я не знаю, есть ли для этого что-то вроде DataContracts.

3. Вы можете использовать [JsonPropertyAttribute] для переименования полей. например, [JsonProperty("format_name")] public string ThisIsTheFormatName { get; set; } и JsonConvert отобразит это.

4. Спасибо, эта работа завершена. Теперь я счастлив. Единственная проблема сейчас в том, что я действительно теперь знаю, как заставить это сериализоваться в Dictionary<string, foo> . Я должен использовать атрибут JsonArrayAttribute, верно? Но большое вам спасибо

Ответ №1:

Вы должны десериализовать этот тип данных в модель, а не в Dictionary , поскольку, похоже, у него фиксированная структура, а не динамическая.

Например, давайте назовем модель «MyMovieData».

 public class MyMovieData
{
    [JsonProperty("streams"]
    public MovieStream[] Streams { get; set; }
}

public class MovieStream[]
{
    [JsonProperty("codec_name")]
    public string CodecName { get; set; }

    [JsonProperty("codec_type")]
    public string CodecType { get; set; }
}
  

Теперь вы можете десериализовать его очень простым способом:

 MyMovieData bigBuckBunnyData = JsonConvert.DeserializeObject<MyMovieData>(json);

MovieStream[] bigBuckBunnyStreams = bigBuckBunnyData.Streams;
  

Комментарии:

1. Да, спасибо, это работает. Я просто надеялся, что он будет в списке с «Video1» => { Type и т.д.}, А не в массиве. Но это абсолютно нормально

2. Тогда вы можете сделать JsonConvert.DeserializeObject<MyMovieData[]>(json) , если у вас есть массив данных. <List<MyMovieData>>(json) Если вы предпочитаете List<> .