// 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. using System.Collections; using System.Collections.Generic; using System.Collections.Generic.Enumerable; using System.IO; using System.Text; namespace System.Diagnostics { public partial class EnhancedStackTrace : StackTrace, IEnumerable { public static EnhancedStackTrace Current() => new EnhancedStackTrace(new StackTrace(1 /* skip this one frame */, true)); private readonly List _frames; // Summary: // Initializes a new instance of the System.Diagnostics.StackTrace class using the // provided exception object. // // Parameters: // e: // The exception object from which to construct the stack trace. // // Exceptions: // T:System.ArgumentNullException: // The parameter e is null. public EnhancedStackTrace(Exception e) { if (e == null) { throw new ArgumentNullException(nameof(e)); } _frames = GetFrames(e); } public EnhancedStackTrace(StackTrace stackTrace) { if (stackTrace == null) { throw new ArgumentNullException(nameof(stackTrace)); } _frames = GetFrames(stackTrace); } /// /// Gets the number of frames in the stack trace. /// /// The number of frames in the stack trace. public override int FrameCount => _frames.Count; /// /// Gets the specified stack frame. /// /// The index of the stack frame requested. /// The specified stack frame. public override StackFrame GetFrame(int index) => _frames[index]; /// /// Returns a copy of all stack frames in the current stack trace. /// /// /// An array of type System.Diagnostics.StackFrame representing the function calls /// in the stack trace. /// public override StackFrame[] GetFrames() => _frames.ToArray(); /// /// Builds a readable representation of the stack trace. /// /// A readable representation of the stack trace. public override string ToString() { if (_frames == null || _frames.Count == 0) return ""; var sb = new StringBuilder(); Append(sb); return sb.ToString(); } internal void Append(StringBuilder sb) { var frames = _frames; 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.Append(sb); var filePath = frame.GetFileName(); if (!string.IsNullOrEmpty(filePath)) { sb.Append(" in "); sb.Append(TryGetFullPath(filePath)); } var lineNo = frame.GetFileLineNumber(); if (lineNo != 0) { sb.Append(":line "); sb.Append(lineNo); } } } EnumerableIList GetEnumerator() => EnumerableIList.Create(_frames); IEnumerator IEnumerable.GetEnumerator() => _frames.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => _frames.GetEnumerator(); /// /// 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; } } }