Если исключение поймано и затем переброшено, то трассировка его стека будет выглядеть так, как если бы исключение произошло в точке переброса, а не в исходном месте. Надеюсь, что в вашем коде не так много всего такого. Если нет, то одной трассировки стека должно быть достаточно, чтобы различить места исключений.
Другая проблема заключается в том, будут ли трассировки стека идентичными, чтобы они не казались двумя разными исключениями, когда они действительно одинаковы. Это также не должно быть проблемой, так как трассировки стека, по моему опыту, идентичны. (Результаты ToString () для объекта исключения, как правило, не будут идентичны.)
ОБНОВЛЕНО
Были некоторые дискуссии о том, каковы именно обстоятельства, что Exception.StackTrace
будет поврежден. Основное правило таково, что в любое время
throw *expression*;
выполняется, тогда для объекта Exception
, который идентифицирует *expression*
, будет установлено свойство StackTrace
. Если *expression*
опущено
throw;
тогда StackTrace не будет задействован.
Мне не удалось найти терминологию для этих двух форм, поэтому я буду называть их «явными» и «неявными» соответственно. Обратите внимание, что не имеет значения, является ли объект исключения, к которому разрешается *expression*
, new
или уже существующим объектом.
Вот программа, иллюстрирующая это поведение:
using System;
namespace FunWithExceptions
{
class Program
{
static void Main(string[] args)
{
try { Replace(); }
catch (InvalidOperationException ex) { DisplayResult("Replace resulted in", ex); }
try { RethrowExplicit(); }
catch (InvalidOperationException ex) { DisplayResult("RethrowExplicit resulted in", ex); }
try { RethrowImplicit(); }
catch (InvalidOperationException ex) { DisplayResult("RethrowImplicit resulted in", ex); }
InvalidOperationException myException = new InvalidOperationException();
DisplayResult("myException starts with", myException);
try { throw myException; }
catch (InvalidOperationException) { }
DisplayResult("myException changes to", myException);
Console.ReadLine();
}
static void ThrowAnException()
{ throw new InvalidOperationException("You messed up!"); }
static void Replace()
{
try { ThrowAnException(); }
catch (InvalidOperationException ex)
{
DisplayResult("Replace caught", ex);
throw new InvalidOperationException("Another mistake.");
}
}
static void RethrowExplicit()
{
try { ThrowAnException(); }
catch (InvalidOperationException ex)
{
DisplayResult("RethrowExplicit caught", ex);
throw ex;
}
}
static void RethrowImplicit()
{
try { ThrowAnException(); }
catch (InvalidOperationException ex)
{
DisplayResult("RethrowImplicit caught", ex);
throw;
}
}
static void DisplayResult(string context, Exception ex)
{
Console.WriteLine("{0} exception thrown at {1}", context, FirstMethodName(ex.StackTrace));
}
private const string methodNamePrefix = " at FunWithExceptions.Program.";
private static object FirstMethodName(string stackTrace)
{
stackTrace = stackTrace ?? string.Empty;
if (stackTrace.StartsWith(methodNamePrefix))
stackTrace = stackTrace.Substring(methodNamePrefix.Length);
int methodNameEndIndex = stackTrace.IndexOf(')');
if (methodNameEndIndex != -1)
stackTrace = stackTrace.Substring(0, methodNameEndIndex + 1);
if (stackTrace.Length > 0)
return stackTrace;
else
return "--empty--";
}
}
}
Эта программа приводит к следующему выводу:
Заменить пойманное исключение, выданное ThrowAnException ()
Замена привела к исключению, выданному в Replace ()
RethrowExplicit перехватил исключение, выданное в ThrowAnException ()
RethrowExplicit привел к исключению, брошенному в RethrowExplicit ()
RethrowImplicit перехватил исключение, выданное в ThrowAnException ()
RethrowImplicit привел к исключению, выданному в ThrowAnException ()
myException начинается с исключения, выданного в --empty -
myException изменяется на исключение, выдаваемое в Main (String [] args)
Шестая строка - интересная.
Теперь я полностью забил эту точку до смерти. : -)