How to hide the current method from exception stack trace in .NET?
Maybe you could derive your own exception type and override the StackTrace
property getter to exclude your method:
using System;
using System.Collections.Generic;
class MyException : Exception {
string _excludeFromStackTrace;
public MyException(string excludeFromStackTrace) {
_excludeFromStackTrace = excludeFromStackTrace;
}
public override string StackTrace {
get {
List<string> stackTrace = new List<string>();
stackTrace.AddRange(base.StackTrace.Split(new string[] {Environment.NewLine},StringSplitOptions.None));
stackTrace.RemoveAll(x => x.Contains(_excludeFromStackTrace));
return string.Join(Environment.NewLine, stackTrace.ToArray());
}
}
}
class Program {
static void TestExc() {
throw new MyException("Program.TestExc");
}
static void foo() {
TestExc();
}
static void Main(params string[] args) {
try{
foo();
} catch (Exception exc){
Console.WriteLine(exc.StackTrace);
}
}
}
Using the code at the end of this answer allows you to write code such as:
[HideFromStackTrace] // apply this to all methods you want omitted in stack traces
static void ThrowIfNull(object arg, string paramName)
{
if (arg == null) throw new ArgumentNullException(paramName);
}
static void Foo(object something)
{
ThrowIfNull(something, nameof(something));
…
}
static void Main()
{
try
{
Foo(null);
}
catch (Exception e)
{
Console.WriteLine(e.GetStackTraceWithoutHiddenMethods());
} // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
} // gets a stack trace string representation
// that excludes all marked methods
Here's one possible implementation:
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method, Inherited=false)]
public class HideFromStackTraceAttribute : Attribute { }
public static class MethodBaseExtensions
{
public static bool ShouldHideFromStackTrace(this MethodBase method)
{
return method.IsDefined(typeof(HideFromStackTraceAttribute), true);
}
}
public static class ExceptionExtensions
{
public static string GetStackTraceWithoutHiddenMethods(this Exception e)
{
return string.Concat(
new StackTrace(e, true)
.GetFrames()
.Where(frame => !frame.GetMethod().ShouldHideFromStackTrace())
.Select(frame => new StackTrace(frame).ToString())
.ToArray()); // ^^^^^^^^^^^^^^^ ^
} // required because you want the usual stack trace
} // formatting; StackFrame.ToString() formats differently
Note that this only causes marked methods to be excluded from one particular representation of the stack trace, not from the stack trace itself. I know of no way to achieve the latter.
P.S.: If all you want is to hide a method in the Call Stack window during a debugging session, simply apply the [DebuggerHidden]
attribute to the method.
I am guessing that you want to do this in order to consolidate code that is used to create the exception?
In that case, rather than write a ThrowException()
function, why not write a GetException()
function? Then in Foo, just do throw GetException();