Частенько при роботі з 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>();
Власне розмістив тут, щоб код не загубити серед своїх конспектів, тому що думаю цей фрагмент мені ще не один раз пригодиться.