ExpandoObject в ZennoPoster

Частенько при роботі з Json в програмі ZennoPoster у своїх проєктах я використовую словник Dictionary<string,object>, але приходиться працювати також з типом даних dynamic. Власне для мене було не очевидним, що для створення dynamic потрібно використовувати ExpandoObject, тому рішив залишити приклад в цій публікації.

Коли пишемо код, хочеться писати приблизно так obj.field=1, і це можливо, коли створювати свій клас.
Проте не завжди хочеться створювати клас, тому що від API може приходити будь-який динамічний об’єкт.
Так от, коли створити об’єкт використовуючи ExpandoObject, появляється можливість працювати з полями, як я описав вище.
Ось фрагмент C# коду, який є корректним і робочим для створення об’єкта dynamic:

dynamic obj = new System.Dynamic.ExpandoObject();
  obj.id = 10;
  obj.name = "Worker";
  obj.lines = new[]{ "Worker" };

Код, виконує приблизно те саме, що і наступний фрагмент:

var obj = new Dictionary<string,object>();
  obj["id"] = 10;
  obj["name"] = "Worker";
  obj["lines"] = new[]{ "Worker" };

Тобто, при серіалізації в JSON результат буде ідентичним.
Але, створення ExpandoObject інколи більше підходить.
Можна також вкладати один ExpandoObject в інший, що також дозволить звертатись через крапочку: obj.task.type.
Ще один фрагмент коду, який використовував в своїх проєктах:

dynamic obj = new System.Dynamic.ExpandoObject();
  obj.api = "apikey";
  obj.task = new System.Dynamic.ExpandoObject();
  obj.task.type = "image";
  obj.task.websiteURL = "https://blog.yosyfovych.te.ua";
  obj.task.websiteKey = "7897-987-87987-4564-32131";
  obj.id = 0;

Наприклад, одного разу мені приходилось створювати динамічний об’єкт.
В залежності від даних, які були одержані в json, відфільтрувати поля.
Тобто створити об’єкт, який би мав тільки необхідні мені поля.
Ось фрагмент коду, який я тоді використовував:

// сама функція фільтрації полів
Func<string, IEnumerable<string>, string> GetObject = (text, includedFields) =>{
  Func<KeyValuePair<string, object>, object> FormatKeyValuePair = (pair) => {
    return pair.Value != null ? pair.Value : string.Empty;
  };
  dynamic data_dic = Global.ZennoLab.Json.JsonConvert.DeserializeObject<System.Dynamic.ExpandoObject>(text);
  var fields = ((IDictionary<string, object>)data_dic)
    .Where(x => includedFields.Contains(x.Key)) // якщо ключ існує
    .ToDictionary(x => x.Key, x => FormatKeyValuePair(x)); // створити об'єкт
  return Global.ZennoLab.Json.JsonConvert.SerializeObject(fields, Global.ZennoLab.Json.Formatting.None);
};
// одержав десь вище невідомий об'єкт data
string json = Global.ZennoLab.Json.JsonConvert.SerializeObject(data, Global.ZennoLab.Json.Formatting.None);
List<string> list =new List<string> { "id", "name" }; // поля для фільтрації
return GetObject(json, list);

Також, коли розбираємо XML чи JSON, то дані також будуть мати тип даних dynamic.
Ось приклад коду, який дає можливість подивитись в лог:

string xml = string.Empty;
project.Xml.FromString(xml);
foreach(dynamic message in project.Xml) {
  project.SendInfoToLog(message.ToString());
}
string json = string.Empty;
project.Json.FromString(json);
foreach(dynamic message in project.Json) {
  project.SendInfoToLog(message.ToString());
}

Також частенько десеріалізую Json в dynamic, проте після десеріалізації частіше приходиться звертатись до об’єкта не через крапочку, наприклад obj.key, а як до словника obj["key"]:

string json = string.Empty;
var obj = Global.ZennoLab.Json.JsonConvert.DeserializeObject<dynamic>(json);
return obj["key"];

Також, часто буває приходиться приводити тип даних, тому що не завжди це може відбуватись автоматично (саме тому є випадки, коли зручніше використовувати Dictionary)

return obj["key"].ToObject<string>();

Власне розмістив тут, щоб код не загубити серед своїх конспектів, тому що думаю цей фрагмент мені ще не один раз пригодиться.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *