2009-01-02 79 views
34

Tôi muốn đặt một số trình xử lý cho tất cả các ngoại lệ không mong muốn mà tôi có thể không gặp phải bên trong mã của mình. Trong Program.Main() Tôi đã sử dụng mã sau:Xử lý vấn đề ngoại lệ chưa được xử lý

AppDomain.CurrentDomain.UnhandledException 
    += new UnhandledExceptionEventHandler(ErrorHandler.HandleException); 

Nhưng nó không hoạt động như tôi mong đợi. Khi tôi bắt đầu ứng dụng trong chế độ gỡ lỗi và ném một ngoại lệ nó đã gọi trình xử lý, nhưng sau đó trình trợ giúp ngoại lệ trong Visual Studio xuất hiện như thể ngoại lệ xảy ra mà không cần xử lý. Tôi đã thử Application.Exit() bên trong trình xử lý nhưng nó cũng không hoạt động.

Điều tôi muốn đạt được là ngoại lệ được xử lý với trình xử lý của tôi và sau đó ứng dụng đóng lại độc đáo. Có cách nào khác để làm điều đó hoặc tôi đang sử dụng mã ở trên theo cách sai?

Trả lời

27

Đó là vì bạn đang chạy nó thông qua Visual Studio ở chế độ Gỡ lỗi. Nếu bạn phát hành và cài đặt ứng dụng của mình ở một nơi khác, không có gì ngoại trừ trình xử lý ngoại lệ toàn cục của bạn sẽ được xử lý.

6

Lưu ý rằng các ngoại lệ chưa được xử lý vẫn khá tử vong; bạn chỉ có thể sử dụng điều này để đăng nhập, hoặc có thể một số đóng cửa vội vàng. Không phải điều này cũng không phải Application.ThreadException có thể được sử dụng như một bồn rửa toàn cầu cho các lỗi.

Cách tiếp cận tốt hơn là thêm xử lý thích hợp - ví dụ: xung quanh toàn bộ logic Main() của bạn. Lưu ý rằng ngay cả điều này không thể bắt được một số ngoại lệ, chẳng hạn như lỗi trong khi tải biểu mẫu (đặc biệt khó chịu - bạn có thể bắt chúng bằng trình gỡ rối được đính kèm nhưng không được đính kèm).

+0

tốt, vâng, tất nhiên tôi biết điều đó;) – agnieszka

+0

thì tại sao không bắt chúng trong Main()? –

+0

"tôi biết rằng" là một câu trả lời cho phần "chìm cho lỗi". tôi đã được dạy thử nắm bắt trong chính là một điều bạn không nên làm. Tuy nhiên, tôi phải nói một cách trung thực rằng tôi không biết tại sao nó sẽ là một cách tiếp cận xấu (tất nhiên nếu tôi bắt tất cả các trường hợp ngoại lệ tôi có thể nghĩ bên trong mã) – agnieszka

31

Thông thường tôi sử dụng một cái gì đó như thế này để thử và nắm bắt tất cả các ngoại lệ cấp cao bất ngờ.

using System; 

static class Program 
{ 
    [STAThread] 
    static void Main(string[] argv) 
    { 
    try 
    { 
     AppDomain.CurrentDomain.UnhandledException += (sender,e) 
     => FatalExceptionObject(e.ExceptionObject); 

     Application.ThreadException += (sender,e) 
     => FatalExceptionHandler.Handle(e.Exception); 

     // whatever you need/want here 

     Application.Run(new MainWindow()); 
    } 
    catch (Exception huh) 
    { 
     FatalExceptionHandler.Handle(huh); 
    } 
    } 

    static void FatalExceptionObject(object exceptionObject) { 
    var huh = exceptionObject as Exception; 
    if (huh == null) { 
     huh = new NotSupportedException(
     "Unhandled exception doesn't derive from System.Exception: " 
     + exceptionObject.ToString() 
    ); 
    } 
    FatalExceptionHandler.Handle(huh); 
    } 
} 

Có thể đây cũng là điều bạn thấy hữu ích? Mã chính này định tuyến tất cả ba cách bắt các ngoại lệ cấp cao bất ngờ thông qua một cuộc gọi phương thức. Tất cả những gì bạn cần bây giờ là một lớp tĩnh FatalExceptionHandler bao gồm xử lý ngoại lệ cấp cao nhất trong phương thức Handle của nó.

Và thực sự, bất kỳ nhà phát triển ứng dụng biết có thực sự chỉ là hai điều cần làm đó:

  1. Hiện/log ngoại trừ như bạn thấy phù hợp
  2. Hãy chắc chắn rằng bạn quá trình thoát/diệt các ứng dụng

Nếu bạn cho rằng mục thứ hai là lạ, hãy nhớ rằng chúng tôi chỉ bận tâm thực hiện điều này ngay từ đầu cho các tình huống thực sự đặc biệt. Những điều này có thể là lỗi cần thay đổi đối với ứng dụng của bạn để được giải quyết chính xác. Bất kỳ xử lý ngoại lệ nào khác - loại chức năng - phải thấp hơn bên trong mã chương trình thực tế của bạn, bắt các loại ngoại lệ cụ thể, điều này có ý nghĩa và xử lý chúng theo cách có ý nghĩa. Bất cứ điều gì khác nên bong bóng lên đến FatalExceptionHandler của bạn để làm cho bản thân biết và ngăn chặn các chương trình có thể làm tê liệt từ làm việc kể từ trạng thái hỏng

chương trình Chết nói không dối trá ... ;-)

+0

+1 cho các chương trình chết không nói dối ... ;-) –

+1

Như bạn có thể thấy từ [Tại sao UnhandledExceptionEventArgs.ExceptionObject một đối tượng và không phải là Ngoại lệ?] (Http://stackoverflow.com/questions/913472/why-is-unhandledexceptioneventargs-exceptionobject-an-object-and-not- một ngoại lệ), nó * có thể * là không khôn ngoan để đưa 'e.ExceptionObject' vào' Exception' mà không kiểm tra trước, vì nó sẽ không luôn luôn là kiểu 'Exception' ... bạn có thể sẽ tạo ra một' mới Ngoại lệ ở đây. – Sheridan

+0

Tự hỏi tại sao nó là đối tượng, nhưng không bao giờ thực sự nhìn vào điều này. Tôi đã học được một cái gì đó mới ngày hôm nay. Cảm ơn! Sẽ thay đổi câu trả lời để thử và khắc phục điều này. – peSHIr

2

Có lẽ những gì bạn đang muốn tìm Environment.Exit(int errorcode)

1

Hành vi đó là do thiết kế.

Nhưng có một công việc xung quanh.

Hoặc bạn gọi Process.GetCurrentProcess().Kill(); trong trình xử lý hoặc đơn giản là không để trình xử lý kết thúc.

Kiểm tra ví dụ:

class Program 
{ 
    void Run() 
    { 
     AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); 

     Console.WriteLine("Press enter to exit."); 

     do 
     { 
      (new Thread(delegate() 
      { 
       throw new ArgumentException("ha-ha"); 
      })).Start(); 

     } while (Console.ReadLine().Trim().ToLowerInvariant() == "x"); 


     Console.WriteLine("last good-bye"); 
    } 

    int r = 0; 

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
    { 
     Interlocked.Increment(ref r); 
     Console.WriteLine("handled. {0}", r); 
     Console.WriteLine("Terminating " + e.IsTerminating.ToString()); 

     Thread.CurrentThread.IsBackground = true; 
     Thread.CurrentThread.Name = "Dead thread";    

     while (true) 
      Thread.Sleep(TimeSpan.FromHours(1)); 
     //Process.GetCurrentProcess().Kill(); 
    } 

    static void Main(string[] args) 
    { 
     Console.WriteLine("..."); 
     (new Program()).Run(); 
    } 
} 

Đây không phải là một bồn rửa mặc định cho trường hợp ngoại lệ, chắc chắn.

Nhưng điều này nên được thực hiện để báo cáo ngoại lệ một cách duyên dáng.