2012-02-09 28 views
7

Il solito consiglio di rilanciare un'eccezione è utilizzare un'istruzione throw; in modo da conservare la traccia dello stack originale. (Example)Trova dove è stata originariamente generata l'eccezione di rethrown utilizzando il debugger di Visual Studio C#?

Tuttavia, quando provo questo semplice esempio, il debugger di Visual Studio non mostra la traccia dello stack originale.

namespace ExceptionTest 
{ 
    class Program 
    { 
     static void ThrowException() 
     { 
      throw new System.Exception(); // The line that I WANT the debugger to show. 
     } 

     static void Main(string[] args) 
     { 
      try 
      { 
       ThrowException(); 
      } 
      catch (System.Exception) 
      { 
       System.Console.WriteLine("An exception was thrown."); 

       throw; // The line that the debugger ACTUALLY shows. 
      } 
     } 
    } 
} 

Come è possibile utilizzare il debugger per trovare la fonte originale dell'eccezione?

+0

possibile duplicato del [C# rigenerare un'eccezione: come ottenere lo stack eccezione nel IDE] (http://stackoverflow.com/questions/4351333/c-sharp-rethrow-an-exception-how-to-get-the-exception-stack-in-the-ide) –

risposta

10

L'opzione migliore è chiedere a Visual Studio di interrompere l'eccezione originale anziché tornare indietro dallo stack trace. Per fare questo:

1) Fare clic sulla voce di menu 'Debug' 2) Fare clic su 'Eccezioni ...' 3) Selezionare 'Eccezioni Common Language Runtime' - '' Gettato

Con questo approccio si potrebbe ottenere più di quanto volessi davvero se ci fossero molte eccezioni generate. È possibile filtrare le eccezioni che interrompe espandendo la lista ad albero.

Vedi Immagine:

enter image description here

+0

Questo vale anche quando non si usa 'throw;' (e fare qualcosa come 'lanciare ex;'), giusto? Quindi qual è il vantaggio dell'uso di 'throw;' invece di 'throw ex;'? –

+0

La finestra Stack chiamate non conterrà il punto in cui si è verificata l'eccezione. La proprietà Exception.StackTrace contiene la traccia dello stack conservata. Seguire i passaggi in questa risposta o leggere la proprietà StackTrace dell'eccezione per determinare la provenienza dell'eccezione. – JamieSee

+0

@ Jon-Eric Se si butta ex; 'invece di' throw; 'la proprietà StackTrace sull'eccezione non avrà la traccia dello stack conservata. Risolvi sempre con 'throw;' o avvolgendo l'eccezione, cioè getta una nuova ApplicationException ("My exception explanation.", Ex); '. – JamieSee

0

Per inciso, in vb.net, si possono utilizzare filtri di eccezione in alcune situazioni come questa in cui si sa non è veramente interessato a prendere un'eccezione - solo trovare fuori che è successo. Se il codice fosse scritto in vb.net e usato un filtro per catturare l'eccezione (probabilmente facendo l'output stesso all'interno del blocco "finally") non ci sarebbe un "catch and rethrow" - il cursore salterà alla fonte dell'eccezione originale (come bonus, vs interromperà il flusso del programma prima che si verifichi lo svolgimento dello stack). Si noti che si può optare per avere vs trap ogni volta che viene lanciata un'eccezione particolare, indipendentemente dal fatto che venga rilevata o meno, ma a volte si è interessati solo ad alcuni dei luoghi in cui viene generata un'eccezione, piuttosto che a tutti.

1

La soluzione migliore che ho trovato è scrivere il callstack Exception su Debug.Console e lasciare che il parser della riga di codice incorporato in Visual Studio fornisca la navigazione.

ho trovato davvero utile quando si tratta di eccezioni non gestite sul AppDomain e WPF Dispatcher come Visual Studio si rompe sempre troppo tardi.

base da un articolo su Code Project, ho modificato è che emetta al Console come un singolo blocco di testo - anziché linea per linea - che era necessario ho registrazione anche iscritto Console.

Uso

public void ReportException(Exception exception) 
{ 
    if (Debugger.IsAttached) 
    { 
     DebugHelper.PrintExceptionToConsole(exception); 
     Debugger.Break(); 
    } 

    // ... 

} 

Fonte

public static class DebugHelper 
{ 
    // Original idea taken from the CodeProject article 
    // http://www.codeproject.com/Articles/21400/Navigating-Exception-Backtraces-in-Visual-Studio 

    private static readonly string StarSeparator = new String('*', 80); 
    private static readonly string DashSeparator = new String('-', 80); 
    private const string TabString = " "; 

    /// <summary> 
    /// Prints the exception using a format recognized by the Visual Studio console parser. 
    /// Allows for quick navigation of exception call stack. 
    /// </summary> 
    /// <param name="exception">The exception.</param> 
    public static void PrintExceptionToConsole(Exception exception) 
    { 
     using (var indentedTextWriter = new IndentedTextWriter(Console.Out, TabString)) 
     {     
      var indentLevel = 0; 
      while (exception != null) 
      { 
       indentedTextWriter.Indent = indentLevel; 
       indentedTextWriter.Write(FormatExceptionForDebugLineParser(exception)); 
       exception = exception.InnerException; 
       indentLevel++; 
      } 
     } 
    } 

    private static string FormatExceptionForDebugLineParser(Exception exception) 
    { 
     StringBuilder result = new StringBuilder(); 

     result.AppendLine(StarSeparator); 
     result.AppendLineFormat(" {0}: \"{1}\"", exception.GetType().Name, exception.Message); 
     result.AppendLine(DashSeparator); 

     // Split lines into method info and filename/line number 
     string[] lines = exception.StackTrace.Split(new string[] { " at " }, StringSplitOptions.RemoveEmptyEntries) 
               .Select(x => x.Trim()) 
               .Where(x => !String.IsNullOrEmpty(x)) 
               .ToArray(); 

     foreach (var line in lines) 
     { 
      string[] parts = line.Split(new string[] { " in " }, StringSplitOptions.RemoveEmptyEntries); 
      string methodInfo = parts[0]; 
      if (parts.Length == 2) 
      { 
       string[] subparts = parts[1].Split(new string[] { ":line " }, StringSplitOptions.RemoveEmptyEntries); 
       result.AppendLineFormat(" {0}({1},1): {2}", subparts[0], Int32.Parse(subparts[1]), methodInfo); 
      } 
      else 
       result.AppendLineFormat(" {0}", methodInfo); 
     } 

     result.AppendLine(StarSeparator); 

     return result.ToString(); 
    } 

} 

Per utilizzare il come è, sarà necessario anche il metodo di cui sopra, di estensione sotto e aggiungere lo spazio dei nomi System.CodeDom.Compiler per IndentedTextWriter.

Metodo di estensione

/// <summary> 
/// Appends the string returned by processing a composite format string followed by the default line terminator. 
/// </summary> 
/// <param name="sb">The StringBuilder.</param> 
/// <param name="format">The format.</param> 
/// <param name="args">The args.</param> 
public static void AppendLineFormat(this StringBuilder sb, string format, params object[] args) 
{ 
    sb.AppendFormat(format, args); 
    sb.AppendLine(); 
} 
1

È possibile utilizzare l'attributo DebuggerNonUserCode.

Vedi http://blogs.msdn.com/b/jmstall/archive/2007/02/12/making-catch-rethrow-more-debuggable.aspx

L'esempio diventa in questo modo:

namespace ExceptionTest 
{ 
    class Program 
    { 
     static void ThrowException() 
     { 
      throw new System.Exception(); // The line that I WANT the debugger to show. 
     } 

     [DebuggerNonUserCode()] 
     static void Main(string[] args) 
     { 
      try 
      { 
       ThrowException(); 
      } 
      catch (System.Exception) 
      { 
       System.Console.WriteLine("An exception was thrown."); 

       throw; // The line that the debugger ACTUALLY shows. 
      } 
     } 
    } 
} 
Problemi correlati