C# Десериализация JSON в класс, зависящий от свойства типа - PullRequest
0 голосов
/ 19 апреля 2020

Допустим, у меня есть небольшой фрагмент json:

{
  "Type": "Bar",
  "BarOnly": "This is a string readable when deserialized to the Bar class only, as declared in my type key"
}

У меня также есть три класса:

public class Base
{
    public enum SampleEnum
    {
        Bar,
        Baz,
    }

    public SampleEnum Type
    {
        get;
        set;
    }
}

public class Bar : Base
{
    public string BarOnly
    {
        get;
        set;
    }
}

public class Baz : Base
{
    public string BazOnly
    {
        get;
        set;
    }
}

На основе свойства Type во фрагменте json Я хотел бы, чтобы он был десериализован в Bar или Baz.
Моя первая идея состояла в том, чтобы сначала десериализовать его в базовый класс, а затем использовать его тип и оператор switch, чтобы снова десериализовать JSON для его соответствующих учебный класс. (Использование Newtonsoft.Json)

var type = JsonConvert.DeserializeObject<Base>(json).Type;
string message = "";
switch (type)
{
    case (Base.SampleEnum.Bar):
        message = JsonConvert.DeserializeObject<Bar>(json).BarOnly;
        break;
    case (Base.SampleEnum.Baz):
        message = JsonConvert.DeserializeObject<Baz>(json).BazOnly;
        break;
}
Console.WriteLine(message);

Нет необходимости говорить, что этот процесс чрезвычайно избыточен, утомителен и, поскольку оператор switch жестко запрограммирован, вовсе не очень «динамичен c».
Другая идея состояла в том, чтобы вместо этого использовать базовый класс generi c и передать тип фактического класса, в который он должен десериализоваться, но затем я получаю тот же оператор switch, чтобы выяснить, каким должен быть этот класс.
Поскольку вы не можете отобразить перечисления на типы классов, я также подумал об использовании словаря для сопоставления возможных значений перечислений с их аналогами классов; это все еще делает процесс отображения жестко запрограммированным.
Есть ли какой-либо способ, которым я могу динамически заставить соответствующий класс десериализоваться в зависимости от свойства типа объекта json?

РЕДАКТИРОВАТЬ: Кажется, есть некоторая путаница о том, как это предполагается использовать и как данные выбираются; позвольте мне предоставить некоторую справочную информацию.
Я перебираю каталог с большим количеством различных файлов электронных таблиц, в основном CSV и XML файлов. У каждого из этих каналов есть «метафайл», описывающий, как обрабатывать их содержимое. Это включает в себя контрольные суммы, разделители и другую информацию. Они также объявляют тип родительского файла (CSV, XML et c). Следовательно, они имеют много общих свойств (например, класс Base в моем примере), но также имеют свой собственный набор свойств. Они происходят от абстрактного класса, который требует от них реализации функции, которая возвращает экземпляр соответствующего класса обработки каналов, инициализированный значениями непосредственно из метакласса. Я надеюсь, что это имеет смысл.

1 Ответ

1 голос
/ 20 апреля 2020

@ ОгузОзгул комментирование верно. Я делал это бесчисленное количество раз для объектов, состоящих из интерфейсов, которые необходимо сериализовать и десериализовать.

См. TypeNameHandling для Newtonsoft: https://www.newtonsoft.com/json/help/html/SerializeTypeNameHandling.htm

Ваш Файл json будет выглядеть немного иначе:

{
    "$type": "SomeNamespace.Bar",
    "BarOnly": "This is a string readable when deserialized to the Bar class only, as declared in my type key"
}

Если вы используете

new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.All
}

Во время сериализации, он добавит полное имя типа всех объектов, чтобы убедиться, что newtonsoft знает какой у них тип во время десериализации (если вы используете те же настройки). Таким образом, вам не нужно писать собственный код для определения типа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...