2

Получаю от сервера ответ в виде JSON:

[{
    "name": "Colombia",
    "alpha2Code": "CO",
    "alpha3Code": "COL",
    "capital": "Bogotá"
}]

Определение класса:

public class Country
{
    public string Name { get; set; }
    public string Alpha2Code { get; set; }
    public string Alpha3Code { get; set; }
    public City Capital { get; set; }
}

Как правильно десериализовать JSON, в котором "capital" строка, а в объекте столица представлена объектом типа City.

Я интересуюсь именно как "правильно" это реализовать с вашей точки зрения. Решение этому ведь уже есть, просто я плохо искал?

P.S: Я думаю в сторону создания DTO, где Capital будет типа string, а потом из него конструировать объект Country.

Благодарю.

  • Да, вы правильно думаете в сторону dto. Технически, конечно можно дополнить штатную десериализацию кастомным парсингом JToken'ов, но это сложно - вы сами через полгода с трудом вспомните что и для чего делалось, а уж править это удовольствие сомнительное. – A K Jun 25 '21 at 08:05
  • @AK, как-то сложно у тебя. Да и если использовать JsonConverter для свойства - уже будет проще. К тому же можно воспользоваться JsonConstructor в котором добавить логику для этого поля. – Grundy Jun 25 '21 at 08:18

2 Answers2

3

Я покажу свою идею, как это побороть без написания сложных конвертеров. Смысл здесь в реализации логики данных в самой модели. Написал бы комментарий, да не влезет это всё туда.

Использую атрибуты, совместимые с System.Text.Json.

public class Country
{
    public string Name { get; set; }
    public string Alpha2Code { get; set; }
    public string Alpha3Code { get; set; }
[JsonPropertyName("capital")]
public string CapitalName
{
    get => Capital?.Name;
    set => Capital = new City(value);
}

[JsonIgnore]
public City Capital { get; set; }

}

public class City { public string Name { get; }

public City(string name)
{
    Name = name;
}

}

Если сериализатор позволяет, то свойство CapitalName можно вообще сделать приватным.

Я не претендую на гениальность и не могу утверждать, насколько правильный или неправильный данный подход. Но с ходу минусов у такой реализации я не вижу.

aepot
  • 49,560
  • 1
    Благодарю за Ваш ответ. Очень интересная реализация, выглядит очень неплохо. Возьму на вооружение :) – Romashov-R Jun 25 '21 at 10:53
  • По факту работать будет, до тех пор, пока какой-нибудь Алжир не построит свой Лондон и не сделает его столицей. =) – Blackmeser Jun 29 '21 at 01:56
  • @Blackmeser не вижу проблем добавить еще одну перегрузку конструктора в будущем, если возникнет такая потребность. – aepot Jun 29 '21 at 06:04
0

Могу предложить ещё один способ.
Делаем в классе City оператор неявного преобразования из строки:

public class City
{
    public static implicit operator City(string value) => new City { Name = value };
    public string Name { get; set; }
}

В результате десериализация проходит успешно.

string json = File.ReadAllText("test.json");
var countries = JsonConvert.DeserializeObject<List<Country>>(json);

Можно ли назвать это "правильным"? Дело вкуса.
Обычно принято использовать конвертеры. Во-первых, они позволяют набить кучу кода. Во-вторых, они привычны большинству разрабов. В третьих, потому что!