// Copyright (c) Ben A Adams. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. namespace DTLib.Ben.Demystifier; public partial class EnhancedStackTrace : StackTrace, IEnumerable { private readonly List _frames; /// /// Initializes a new instance of the System.Diagnostics.StackTrace class using the /// provided exception object /// public EnhancedStackTrace(Exception e) { _frames = GetFrames(new StackTrace(e, true)); } public EnhancedStackTrace(StackTrace stackTrace) { _frames = GetFrames(stackTrace); } /// The number of frames in the stack trace. public override int FrameCount => _frames.Count; IEnumerator IEnumerable.GetEnumerator() => _frames.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _frames.GetEnumerator(); public static EnhancedStackTrace Current() => new EnhancedStackTrace(new StackTrace(1 /* skip this one frame */, true)); /// The index of the stack frame requested. /// The specified stack frame. public override StackFrame GetFrame(int index) => _frames[index]; /// a copy of all stack frames in the current stack trace. public override StackFrame[] GetFrames() => _frames.ToArray(); /// /// Builds a readable representation of the stack trace. /// public override string ToString() { if (_frames.Count == 0) return ""; var sb = new StringBuilder(); AppendTo(sb); return sb.ToString(); } public void AppendTo(StringBuilder sb) { var count = _frames.Count; for (var i = 0; i < count; i++) { if (i > 0) sb.Append(Environment.NewLine); var frame = _frames[i]; sb.Append(" at "); frame.MethodInfo.AppendTo(sb); var fileName = frame.GetFileName(); if (!string.IsNullOrEmpty(fileName)) { sb.Append(" in "); sb.Append(TryGetFullPath(fileName!)); } var lineNo = frame.GetFileLineNumber(); if (lineNo != 0) { sb.Append(":line "); sb.Append(lineNo); } } } /// /// Tries to convert a given to a full path. /// Returns original value if the conversion isn't possible or a given path is relative. /// public static string TryGetFullPath(string filePath) { if (Uri.TryCreate(filePath, UriKind.Absolute, out var uri) && uri.IsFile) return Uri.UnescapeDataString(uri.AbsolutePath); return filePath; } }