Why does the high part of the stack (in Exception.StackTrace) gets truncated? Let\'s see a simple example:
public void ExternalMethod()
{
InternalMethod();
}
This is often caused by the compiler optimizations.
You can decorate methods you do not want to inline by using the following attribute:
[MethodImpl(MethodImplOptions.NoInlining)]
public void ExternalMethod()
{
InternalMethod();
}
I know that in a catch block if you do throw ex;
it truncates the stack trace at that point. It's possible that it's "by design" for throw since just throw;
doesn't truncate the stack in a catch. Same may be going on here since you're throwing a new exception.
What happens if you cause an actual exception (i.e. int i = 100/0;
)? Is the stack trace still truncated?
Ok, now I see what your getting at... Sorry for my confusion on the inlining thing.
The 'stack' in a caught exception is only a delta from the currently executing catch block to where the exception was thrown. Conceptually this behavior is correct in that the Exception.StackTrack tells you where the exception occurred within the context of this try/catch block. This allows exception stacks to be forwarded across 'virtual' calls and still maintain accuracy. One classic example of this being done is .Net Remoting exceptions.
Thus if you want a complete stack report in the catch block you would add the current stack to the exception's stack as in the example below. The only problem is this can be more expensive.
private void InternalMethod()
{
try
{
ThrowSomething();
}
catch (Exception ex)
{
StackTrace currentStack = new StackTrace(1, true);
StackTrace exceptionStack = new StackTrace(ex, true);
string fullStackMessage = exceptionStack.ToString() + currentStack.ToString();
}
}
As csharptest said this is by design. The StackTrace stops at the try block. Further more there is no hook in the framework that is called when an exception is thrown.
So the best you can do is something along these lines, it its an absolute requirement to get full stack traces (store a full trace on exceptions creation):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.CompilerServices;
using System.Diagnostics;
namespace ConsoleApplication15 {
[global::System.Serializable]
public class SuperException : Exception {
private void SaveStack() {
fullTrace = Environment.StackTrace;
}
public SuperException() { SaveStack(); }
public SuperException(string message) : base(message) { SaveStack(); }
public SuperException(string message, Exception inner) : base(message, inner) { SaveStack(); }
protected SuperException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
private string fullTrace;
public override string StackTrace {
get {
return fullTrace;
}
}
}
class Program {
public void ExternalMethod() {
InternalMethod();
}
public void InternalMethod() {
try {
ThrowIt();
} catch (Exception ex) {
Console.WriteLine(ex.StackTrace);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
public void ThrowIt() {
throw new SuperException();
}
static void Main(string[] args) {
new Program().ExternalMethod();
Console.ReadKey();
}
}
}
Outputs:
at System.Environment.get_StackTrace() at ConsoleApplication15.SuperException..ctor() in C:\Users\sam\Desktop\Source \ConsoleApplication15\ConsoleApplication15\Program.cs:line 17 at ConsoleApplication15.Program.ThrowIt() in C:\Users\sam\Desktop\Source\Cons oleApplication15\ConsoleApplication15\Program.cs:line 49 at ConsoleApplication15.Program.InternalMethod() in C:\Users\sam\Desktop\Sour ce\ConsoleApplication15\ConsoleApplication15\Program.cs:line 41 at ConsoleApplication15.Program.Main(String[] args) in C:\Users\sam\Desktop\S ource\ConsoleApplication15\ConsoleApplication15\Program.cs:line 55 at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, C ontextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart()
It is not possible to inject this behaviour into the existing System defined exceptions, but .Net has a rich infrastructure for wrapping exceptions and rethrowing so it should not be a huge deal.