Trên thực tế, có một số tình huống mà thống kê throw
sẽ không lưu giữ thông tin StackTrace. Ví dụ: trong mã dưới đây:
try
{
int i = 0;
int j = 12 / i; // Line 47
int k = j + 1;
}
catch
{
// do something
// ...
throw; // Line 54
}
StackTrace sẽ chỉ ra rằng dòng 54 đã đưa ra ngoại lệ, mặc dù nó được nâng lên ở dòng 47.
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
at Program.WithThrowIncomplete() in Program.cs:line 54
at Program.Main(String[] args) in Program.cs:line 106
Trong các tình huống như mô tả ở trên, có hai tùy chọn để dự đoán StackTrace ban đầu:
Gọi Exception.IternalPreserveStackTrace
Vì nó là một phương thức riêng tư, nó phải được gọi bằng cách sử dụng sự phản chiếu:
private static void PreserveStackTrace(Exception exception)
{
MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
BindingFlags.Instance | BindingFlags.NonPublic);
preserveStackTrace.Invoke(exception, null);
}
Tôi có một bất lợi là dựa vào một phương thức riêng tư để lưu giữ thông tin StackTrace. Nó có thể được thay đổi trong các phiên bản tương lai của .NET Framework. Ví dụ mã ở trên và giải pháp đề xuất bên dưới được trích xuất từ weblog Fabrice MARGUERIE .
Gọi ngoại lệ.SetObjectData
Kỹ thuật dưới đây được Anton Tykhyy đề xuất là câu trả lời cho Trong C #, làm thế nào tôi có thể chia sẻ lại InternalException mà không mất câu hỏi theo dõi ngăn xếp .
static void PreserveStackTrace (Exception e)
{
var ctx = new StreamingContext (StreamingContextStates.CrossAppDomain) ;
var mgr = new ObjectManager (null, ctx) ;
var si = new SerializationInfo (e.GetType (), new FormatterConverter ()) ;
e.GetObjectData (si, ctx) ;
mgr.RegisterObject (e, 1, si) ; // prepare for SetObjectData
mgr.DoFixups () ; // ObjectManager calls SetObjectData
// voila, e is unmodified save for _remoteStackTraceString
}
Mặc dù, nó có lợi thế là chỉ dựa vào các phương thức công khai, nhưng nó cũng phụ thuộc vào hàm tạo ngoại lệ sau (một số trường hợp ngoại lệ do bên thứ 3 phát triển không thực hiện):
protected Exception(
SerializationInfo info,
StreamingContext context
)
Trong tình huống của tôi, tôi đã phải chọn cách tiếp cận đầu tiên, bởi vì các ngoại lệ được đưa ra bởi thư viện của bên thứ 3 mà tôi đang sử dụng đã không triển khai hàm tạo này.