A Flat Dictionary Serializer in C#
Recently I have been working with rather large YAML config files and I was wondering if there was an easy way to diff them. Gron is a pretty cool command line tool which claims to make JSON greppable by transforming it into discrete assignments. It turns out that this format is also a great input for diff tools if you sort the assignments. I stumbled over this blog post in which the author presents a similar transformation for C# objects. After some minor tweaks I came up with my own implementation based on the first dynamic solution of said post:
public static class FlatDictionarySerializer { public static Dictionary<string, string?> Serialize( object? obj, string name = "") { var dictionary = new Dictionary<string, string?>(); Flatten(dictionary, obj, name); return dictionary; } private static void Flatten( IDictionary<string, string?> dictionary, object? obj, string prefix) { if (obj == null) { dictionary.Add(prefix, null); return; } var objType = obj.GetType(); if (objType.IsValueType || objType == typeof(string)) { dictionary.Add(prefix, obj.ToString()); } else if (obj is IEnumerable subObjects) { var counter = 0; foreach (var subObj in subObjects) { Flatten(dictionary, subObj, $"{prefix}[{counter++}]"); } } else { var properties = objType.GetProperties().Where(x => x.CanRead); foreach (var property in properties) { Flatten( dictionary, property.GetValue(obj), string.IsNullOrEmpty(prefix) ? property.Name : $"{prefix}.{property.Name}"); } } } }
Note: Adding support for dictionaries only makes sense for a type signature of
IDictionary<string, object>
since other key types such as random objects might
be hard to "stringify".
Update 2022-09-11: Another alternative is to use difftastic, which also supports JSON and YAML files.