2010-08-23 29 views
10

Tôi có sự phụ thuộc vào .NET 2.0 SP2 trong ứng dụng ClickOnce được triển khai của mình (phương pháp ApplicationDeployment.CurrentDeployment.CheckForDetailedUpdate(false) chỉ là SP2).Tại sao nó không thể bắt MissingMethodException?

Tôi muốn kiểm tra xem SP2 có xuất hiện trong khi khởi động ứng dụng hay không. Tôi đã cố gắng để phát hiện điều này bằng cách bắt MissingMethodException sau khi gọi một phương pháp SP2-chỉ.

/// <summary> 
    /// The SP2 bootstrapper does not allow HomeSite installation 
    /// http://msdn.microsoft.com/en-us/vstudio/bb898654.aspx 
    /// So we only advice the user to download .NET 2.0 SP2 manually. 
    /// </summary> 
    private void CheckDotNet2SP() 
    { 
     WaitHandle wh = new AutoResetEvent(true); 
     try 
     { 
      wh.WaitOne(1); //this method is .NET 2.0 SP2 only 
     } 
     //NOTE: this catch does not catch the MissingMethodException 
     catch (Exception) //change to catch(MissingMethodException) does not help 
     { 
      //report that .NET 2.0 SP2 is missing 
     } 
     finally 
     { 
      wh.Close(); 
     } 
    } 

Mã trong lệnh bắt đầu không bao giờ thực thi khi chạy trên .NET 2.0 mà không có SP2. Ngoại lệ chỉ bị bắt bởi trình xử lý sự kiện AppDomain.CurrentDomain.UnhandledException.

Làm cách nào để có thể nhận ra MissingMethodException? Tôi có thể tưởng tượng rằng đây là một trường hợp đặc biệt - CLR chạm vào một phương thức không tồn tại và bằng cách nào đó nó không thể truyền điều này đến khối catch. Tôi muốn hiểu nguyên tắc đằng sau điều này.

Bất kỳ ai có bất kỳ tài nguyên nào về vấn đề này? Có bất kỳ trường hợp ngoại lệ nào khác không thể bị bắt trong một khối đánh bắt không?

Trả lời

13

Tôi nghi ngờ điều này xảy ra vào thời điểm JIT, trước khi phương pháp này được nhập chính xác - tức là trước khi khối catch của bạn bị trúng. Đó là có thể nếu bạn bắt được MissingMethodException trong phương thức gọi, điều này sẽ phân loại nó ... đặc biệt nếu bạn trang trí CheckDotNet2SP với MethodImpl[MethodImplOptions.NoInlining]. Nó vẫn có vẻ như nó sẽ được khá dicey mặc dù.

Bạn luôn có thể kiểm tra sự hiện diện của phương pháp với sự phản chiếu thay vì bằng cách cố gọi nó.

10

Có một vài ngoại lệ đã được xác định là "không thể khôi phục". Một trong số chúng là MissingMethodException, vì nếu một phương thức bị thiếu trong một lớp, đây là một lỗi nghiêm trọng và nó yêu cầu dỡ lớp và nạp lại một lớp mới để phục hồi, điều này không thể thực hiện được (nếu có).

Để khôi phục, bạn cần phải cài đặt lại, kiểm tra các phiên bản của các hội đồng, kiểm tra xem những hình ảnh PE có giá trị, vv

Nếu tất cả các bạn muốn biết là liệu SP2 được cài đặt, phương pháp mặc định là sử dụng một ứng dụng khởi động mà chỉ cần kiểm tra phiên bản đã cài đặt. Nếu tất cả đều ổn, nó chạy ứng dụng, nếu nó không hiển thị một thông điệp tốt đẹp.


Cập nhật theo yêu cầu của OP: trường hợp ngoại lệ
khác hoặc là khó để bắt hoặc uncatchable (có thể phụ thuộc vào phiên bản của .NET, nghĩa là, .NET 4.0 thêm nhiều uncatchables): OutOfMemoryException (có thể bị bắt khi đồng bộ), StackOverflowException (không bao giờ có thể bị bắt), ThreadAbortException (có thể bị bắt, nhưng đặc biệt vì nó sẽ tự động bị reraised ở cuối khối catch), BadImageFormatExceptionMissingManifestResourceException nếu bạn muốn bắt nó trong lắp ráp ném ngoại lệ (nếu bạn tải nó động, giống như với MissingMethodException, bạn có khả năng bắt nó). Và nói chung, bất kỳ ngoại lệ nào không kế thừa từ Exception rất khó nắm bắt (nhưng bạn có thể bắt chúng ngoại trừ khối try/catch chung).

Có những người khác, nhưng ba trường hợp đầu tiên ở trên là những thứ bạn thường gặp nhất trong thực tế.

+0

bạn có thể liệt kê các loại ngoại lệ 'không thể khôi phục' khác không? – Marek

+0

@Marek: đã xong, tôi đã cập nhật câu trả lời. – Abel

+1

Bạn có tham chiếu cho những ngoại lệ "không thể khôi phục" này không? Tôi thấy nó được nhắc đến trong [Application.DispatcherUnhandledException] (http://msdn.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception%28v=vs.85%29.aspx), nhưng tôi không thể tìm thấy thông tin dứt khoát. –

3

Ngoại lệ được ném vào bước biên dịch JIT, vì vậy bạn đã không tham gia vào phương pháp. Thử phiên bản này:

private bool CheckDotNet2SP() 
    { 
     try 
     { 
      CheckImpl(); 
      return true; 
     } 
     catch (MissingMethodException) 
     { 
      return false; 
     } 
    } 

    [MethodImpl(MethodImplOptions.NoInlining)] 
    private void CheckImpl() 
    { 
     using (var wh = new ManualResetEvent(true)) 
      wh.WaitOne(1); 
    } 
+0

Tuy nhiên, phương pháp này sẽ vẫn tải xuống ứng dụng khi có lỗi vì nó được coi là không thể khôi phục. – Abel

3

Bạn có thể sử dụng phản ánh để xem liệu phương pháp có tồn tại hay không.

private void CheckDotNet2SP() 
{ 
    return typeof(WaitHandle).GetMethod("WaitOne", new Type[] { typeof(int) }) 
     != null; 
} 
+0

Lưu ý rằng thao tác này sẽ không hoạt động nếu ngoại lệ được thực thi bởi trình biên dịch JIT. Nó sẽ chỉ hoạt động khi cuộc gọi đến phương thức được thực hiện bằng cách phản ánh. – Abel

Các vấn đề liên quan