Flattening .NET Exceptions and Simple Hierarchies

Home / Flattening .NET Exceptions and Simple Hierarchies

Exceptions in .NET can be difficult to log or inspect due to their hierarchical nature with inner exceptions. Since the InnerException on a given exception is not an enumerated list, it requires a little bit of work to flatten the hierarchy.


Using generic extensions, it pretty easy to flatten any given object which has the structure of a .NET exception (Parent -> Child1 -> Child2 -> Child3) where each child is mapped to a single instance property on the parent. An expression passed to the extension will define which property is the child.

public static class Extensions
{
	// Flatten any object of type TSource that has a single child of type TSource
	public static IEnumerable<TSource> Flatten<TSource>(this TSource source, Expression<Func<TSource, object>> expression)
	{
		var tobj = source;

		var memberExpression = (MemberExpression)expression.Body;
		var propertyInfo = (PropertyInfo)memberExpression.Member;
		do
		{
			yield return tobj;
			tobj = (TSource)propertyInfo.GetValue(tobj);
		}
		while (tobj != null);		
	}
}

Then, to use the extension, it might look like the below code. I’m defining a nested Exception and then using the extension and a LINQ aggregate to get a single string containing all exception messages.

void Main()
{
	// Create a nested exception
	var exception = new Exception("message",
		new Exception("inner message1",
			new Exception("inner message2",
				new Exception("", // No message
					new Exception("inner message4")
				)
			)
		)
	);
			
	var message = exception
		.Flatten<Exception>(x => x.InnerException)
		.Where(x => !string.IsNullOrWhiteSpace(x.Message))
		.Select(x => x.Message)
		.Aggregate((current, next) => $"{current} | {next}");

	Console.WriteLine(message);
}

The nice thing about the extension method is that it is can be used for, essentially, any type rather than being limited to Exceptions specifically.

Leave a Reply