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.