/// <summary> /// Allows you to create a deep and detailed representation of an object tree, including properties of the objects. /// Useful for debugging and reporting scenarios where <see cref="Object.ToString"/> simply does not give enough information. /// </summary> /// <remarks> /// The maximum object tree depth is limited, to avoid outputting too deep (or potentially infinite) hierarchies. /// Repeated objects are referred to by object ID, not output multiple times, to make the output more concise. /// /// <para>Not everything is displayed - there is some fitering and transformation done. The specifics are not listed here. /// Some types have special handing to make them more meaningful (e.g. System.String, IEnumerable).</para> /// /// <para>Generally, the data returned varies per type and may change in the future. /// Do not rely on the output remaining same in future versions, even for the same object.</para> /// </remarks> public static string ToDebugString(this HelpersContainerClasses.Debug container, object o) { Helpers.Argument.ValidateIsNotNull(o, nameof(o)); StringBuilder s = new StringBuilder(); var visitedObjects = new List <object>(); CreateDebugString(o, s, 0, visitedObjects); return(s.ToString()); }
/// <summary> /// Just to state what exactly we are dealing with when an app starts up. /// </summary> public static string GetLoadedAssembliesInfodump(this HelpersContainerClasses.Debug container) { var sb = new StringBuilder(); sb.AppendLine("Loaded assemblies:"); var loadedAssemblyNames = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetName()); // We filter out system assemblies because they are boring. foreach (var assemblyName in loadedAssemblyNames .Where(a => !a.Name.StartsWith("System.")) .OrderBy(a => a.Name)) { sb.AppendLine($"{assemblyName.Name} {assemblyName.Version}"); } return(sb.ToString()); }
/// <summary> /// Gets the Message properties of an exception and all its inner exceptions and all the exception type names. /// /// Useful if you have top-level exceptions with pointless generic messages but also want to see deeper /// without spamming out the entire call stack information for every exception. /// </summary> public static string GetAllExceptionMessages(this HelpersContainerClasses.Debug container, Exception ex) { var sb = new StringBuilder(); var indentLevel = 0; void AppendException(Exception e) { if (e is AggregateException aex) { if (aex.InnerExceptions.Count == 1) { AppendException(aex.InnerException); return; } sb.AppendLine($"AggregateException"); indentLevel++; foreach (var inner in aex.InnerExceptions) { sb.AppendLine("Aggregate member:"); AppendException(inner); } indentLevel--; } else { sb.AppendLine($"{e.Message} ({e.GetType().Name})"); if (e.InnerException != null) { AppendException(e.InnerException); } } } AppendException(ex); // We don't want the last newline, thanks. return(sb.ToString().Trim('\r', '\n')); }