Как заставить десериализатор c # NewtonSoft использовать уже созданный объект для десериализации - PullRequest
0 голосов
/ 24 апреля 2018

при этом

JsonConvert.DeserializeObject(value, type);

Создан новый объект с заданным type для десериализации. Каково мое требование, я хочу использовать уже созданный объект для десериализации

CustomObject obj = new CustomObject(); //passing constructor args
JsonConvert.DeserializeObject(value, obj);    

Но эта перегрузка недоступна.

Итак, есть ли обходной путь, чтобы я мог использовать уже созданный объект вместо создания нового типа через Deserializer .?

Почему я хочу это сделать? (Detail)

Я пишу обобщенный преобразователь из JSON в классы c #. Структура JSON выглядит как

  {
    "ActionType" : "LogEvent", //this is actually class name in a specific namespace
    "Settings"   : {
           "FailureRetries" : 4,
           "LogChannel"     : 1234 // log channel id, implementation detail
     }
  }

То, что я делаю в маппере конфигурации, выглядит следующим образом

public void IAction GetActionFromConfig(){

    dynamic config = configManager.Load<dynamic>(); //loads JSON file.
    string className = config.ActionType; //from config we will get file name.
    Type type = Type.GetType(nameSpaceForConfig + "." + className);

    string  settingValue = JsonConvert.SerializeObject(config.Settings);
    object actionObject = JsonConvert.DeserializeObject(settingValue, type);

    return (IAction)actionObject; // return the IAction from config.
}

Моя проблема в том, что классы реализации IAction могут иметь некоторые зависимости в конструкторе (например, ILogger), и по умолчанию десериализация не инициализирует параметр конструктора. Я знаю, что могу переопределить JsonConverter для инициализации конструктора, но так как я пишу универсальный маппер, я не могу дать конкретные аргументы, используя custom JsonConverter.

Вначале я планирую создать словарь, который будет сопоставлять Type (c # Type class) с конкретной реализацией для разрешения зависимостей.

Во-вторых, я получу конструкторы с заданным типом действия (тип указан в конфигурации с параметром ActionType)

Type type = Type.GetType(nameSpaceForConfig + "." + className);
var ctors = typeof(type).GetConstructors();
var ctor = ctors[0];
List<Type> constructorArguments = new List<Type();
foreach (var param in ctor.GetParameters())
{
     constructorArguments.Add(param.ParameterType);
}

Затем я сделаю запрос к словарю, созданному на шаге 1., чтобы получить аргументы для конструктора.

Наконец, я буду использовать Activator.CreateInstance() (передавая зависимости конструктора, полученные на предыдущем шаге).

А затем используйте этот объект для десериализации для инициализации открытых свойств через файл конфигурации.

Так вот почему я хочу, чтобы десериализация произошла на object, а не на type.

ПРИМЕЧАНИЕ: Предварительное условие - каждое действие должно иметь один конструктор со всеми зависимостями.

в сторону: configManager.Load<T> реализация

public T Load<T>() where T : class, new() => Load(typeof(T)) as T;
public object Load(Type type)
{
  if (!File.Exists(_configurationFilePath))
    return Activator.CreateInstance(type);

  var jsonFile = File.ReadAllText(_configurationFilePath);

  return JsonConvert.DeserializeObject(jsonFile, type, JsonSerializerSettings);
}

1 Ответ

0 голосов
/ 24 апреля 2018

Вы должны использовать метод JsonConvert.PopulateObject для заполнения существующего объекта. Смотри здесь .

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