Exceptionally Lazy

I’m working on a .NET project and have been building an Unhandled Exception Manager in the spirit of Jeff Atwood’s friendly exception handling. If a user encounters an error that will crash our application, the Unhandled Exception Manager steps in first and issues a friendly message. In the background it emails the development team about the exception in as much detail as it can possibly grab.

Recently some unwanted functionality gave me the opportunity to learn about lazy evaluation in C#. Look at the following code:
return MultiLine(
"Date and Time: " + DateTime.Now,
"Machine Name: " + Environment.MachineName,
"IP Address: " + Dns.GetHostEntry(Dns.GetHostName()).AddressList[0],
"Application Domain: " + AppDomain.CurrentDomain.FriendlyName,
"Assembly Codebase: " + _assemblyInfo.CodeBase,
"Assembly Full Name: " + _assemblyInfo.FullName,
"Assembly Version: " + _assemblyInfo.Version,
EnhancedStackTrace(new StackTrace(true))
);

Multiline simply aggregates the lines so that I can print pretty messages both in the code and in my emails:

static string MultiLine(params string[] args)
{
return string.Join(Environment.NewLine, args);
}

If any one of these nested calls throws an exception, we get an unhandled exception in the unhandled exception manager. Not good. Wrapping the whole thing in a try/catch prevents this but will not give us the maximum amount of information. If Dns.GetHostName returns null, for example, it would still be nice to get the MachineName and assembly information. The following MSpec test illustrates the problem:


[Subject(typeof (ExceptionMessageBuilder), "SystemInfo")]
class when_an_exception_is_thrown : ExceptionMessageBuilderSpec
{
private static Exception Exception;
private static Version Version;

private Establish context = () =>
{
Exception = new Exception();
Version = new Version(1, 0, 0, 254);
AssemblyInfo.WhenToldTo(x => x.FullName).Throw(Exception);
AssemblyInfo.WhenToldTo(x => x.Version).Return(Version);
};

private It will_handle_the_exception = () => ExceptionMessageBuilder.SystemInfo();
}

I was able to make this test pass and extract the maximum amount of information about my application crash using lazy evaluation:


public string SystemInfo()
{
return MultiLazy(new List<Lazy<string>>
{new Lazy<string>(() => "Date and Time: " + AppDomain.CurrentDomain.FriendlyName),
new Lazy<string>(() => "Machine Name: " + Environment.MachineName),
new Lazy<string>(() => "IP Address: " + Dns.GetHostEntry(Dns.GetHostName()).AddressList[0]),
new Lazy<string>(() => "Application Domain: " + AppDomain.CurrentDomain.FriendlyName),
new Lazy<string>(() => "Assembly Codebase: " + _assemblyInfo.CodeBase),
new Lazy<string>(() => "Assembly Full Name: " + _assemblyInfo.FullName),
new Lazy<string>(() => "Assembly Version: " + _assemblyInfo.Version),
new Lazy<string>(() => EnhancedStackTrace(new StackTrace(true)))
});
}

Using the Lazy<> syntax, I can state my intentions without executing any of the code. Instead, the CLR compiles the code and waits for .Value to be called on the arguments before executing.  A change to our MultiLine function demonstrates this in action:


static string MultiLazy(List<Lazy<string>> args)
{
var stringBuilder = new StringBuilder();
foreach (var arg in args)
{
try
{
stringBuilder.Append(arg.Value);
}
// ReSharper disable EmptyGeneralCatchClause -- we want all the information we can get.
catch (Exception) {}
// ReSharper restore EmptyGeneralCatchClause
}
return stringBuilder.ToString();
}

Of course, this is my first attempt at lazy evaluation in C# and I’m open to other methods. Could this be cleaned up? Are there better approaches out there?