Bạn có thể bắt một ngoại lệ gốc trong mã C # không?


76

Trong mã C #, bạn có thể bắt được một ngoại lệ gốc được đưa ra từ sâu trong một thư viện không được quản lý nào đó không? Nếu vậy, bạn có cần phải làm bất cứ điều gì khác để nắm bắt nó hoặc một tiêu chuẩn thử ... bắt lấy nó?

Câu trả lời:


35

Bạn có thể sử dụng Win32Exception và sử dụng thuộc tính NativeErrorCode của nó để xử lý nó một cách thích hợp.

// http://support.microsoft.com/kb/186550
const int ERROR_FILE_NOT_FOUND = 2;
const int ERROR_ACCESS_DENIED = 5;
const int ERROR_NO_APP_ASSOCIATED = 1155; 

void OpenFile(string filePath)
{
    Process process = new Process();

    try
    {
        // Calls native application registered for the file type
        // This may throw native exception
        process.StartInfo.FileName = filePath;
        process.StartInfo.Verb = "Open";
        process.StartInfo.CreateNoWindow = true;
        process.Start();
    }
    catch (Win32Exception e)
    {
        if (e.NativeErrorCode == ERROR_FILE_NOT_FOUND || 
            e.NativeErrorCode == ERROR_ACCESS_DENIED ||
            e.NativeErrorCode == ERROR_NO_APP_ASSOCIATED)
        {
            MessageBox.Show(this, e.Message, "Error", 
                    MessageBoxButtons.OK, 
                    MessageBoxIcon.Exclamation);
        }
    }
}

7
Tôi tin rằng điều này không tự động, nhưng chỉ được thực hiện khi bạn sử dụng chữ ký P / Invoke chỉ định nó. Và nó được ném dựa trên mã lỗi Win32, không phải là một ngoại lệ Win32.
Curt Hagenlocher 29/09/08

15

Catch without () sẽ bắt các ngoại lệ không tuân thủ CLS bao gồm các ngoại lệ gốc.

try
{

}
catch
{

}

Xem quy tắc FxCop sau để biết thêm thông tin http://msdn.microsoft.com/en-gb/bb264489.aspx


11
Đúng, điều này là đúng. Tôi chỉ phát hiện ra điều này sau một vài giờ đặc biệt khó chịu dành để so sánh các tệp nhật ký và mã và nghĩ rằng tôi đã đánh mất nó. Tuy nhiên, câu hỏi tiếp theo rõ ràng là bạn có thể xác định loại ngoại lệ gốc từ bên trong khối bắt trống không? Bạn có thể ghi lại bất cứ điều gì hữu ích để xác định nguồn gốc của ngoại lệ không?
Tyson

11

Lớp tương tác giữa C # và mã gốc sẽ chuyển đổi ngoại lệ thành một biểu mẫu được quản lý, cho phép mã C # của bạn bắt được ngoại lệ. Kể từ .NET 2.0, catch (Exception)sẽ gặp bất kỳ lỗi nào khác ngoài lỗi không thể khôi phục.


3
Trong .NET 1.x, nó có thể cho một ngoại lệ được ném mà không xuất phát từ lớp Exception, nhưng khả năng này bị tắt theo mặc định trong 2.0
Curt Hagenlocher

4
Trong C ++, bạn có thể ném bất kỳ đối tượng nào, vì vậy đối với các vấn đề tương tác, việc bắt một đối tượng không bắt nguồn từ Exception là rất hữu ích. Một kịch bản phổ biến là chương trình C ++ sẽ chỉ ném một Chuỗi (thông báo lỗi).
MattDavey

5

Ở đâu đó bằng cách sử dụng .NET Reflector, tôi đã thấy đoạn mã sau:

try {
  ...
} catch(Exception e) {
  ...
} catch {
  ...
}

Hmm, C # không cho phép ném một ngoại lệ không bắt nguồn từ lớp System.Exception. Và theo như tôi đã biết, bất kỳ cautch ngoại lệ nào bởi bộ điều phối tương thích đều được bao bọc bởi lớp ngoại lệ kế thừa System.Exception.

Vì vậy, câu hỏi của tôi là liệu có thể bắt được một ngoại lệ không phải là System.Exception hay không.


1
Có thể phát ra hoặc tạo IL ném một đối tượng tùy ý. Trình biên dịch C # sẽ không cho phép bạn làm điều đó, nhưng các trình biên dịch khác có thể, hoặc như tôi đã nói, bạn có thể phát trực tiếp IL. Một câu lệnh catch không có kiểu sẽ bắt các đối tượng tùy ý cũng như các đối tượng kế thừa Exception.
technophile 29-08

5

Điều này phụ thuộc vào loại ngoại lệ bản địa mà bạn đang nói đến. Nếu bạn đang đề cập đến một ngoại lệ SEH thì CLR sẽ thực hiện một trong hai điều.

  1. Trong trường hợp mã lỗi SEH đã biết, nó sẽ ánh xạ nó tới ngoại lệ .Net thích hợp (tức là OutOfMemoryException)
  2. Trong trường hợp mã không thể lập bản đồ (E_FAIL) hoặc mã không xác định, nó sẽ chỉ ném một phiên bản SEHException .

Cả hai điều này sẽ được bắt bằng một khối "catch (Exception)" đơn giản.

Loại ngoại lệ gốc khác có thể vượt qua ranh giới riêng / được quản lý là ngoại lệ C ++. Tôi không chắc chúng được ánh xạ / xử lý như thế nào. Tôi đoán là vì Windows triển khai các ngoại lệ C ++ trên SEH, chúng chỉ được ánh xạ theo cùng một cách.


Windows implements C++ exceptions on top of SEH- điều này dường như chỉ đúng với VC?
Wolf,

3

Hầu như, nhưng không hoàn toàn. Bạn sẽ bắt được ngoại lệ với

try 
{
  ...
}
catch (Exception e)
{
  ...
}

nhưng bạn vẫn sẽ có những vấn đề tiềm ẩn. Theo MSDN , để đảm bảo các trình hủy ngoại lệ được gọi, bạn sẽ phải bắt như:

try
{
  ...
}
catch
{
  ...
}

Đây là cách duy nhất để đảm bảo một trình hủy ngoại lệ được gọi (mặc dù tôi không chắc tại sao). Nhưng điều đó khiến bạn phải đánh đổi tính vũ phu với khả năng bị rò rỉ bộ nhớ.

Ngẫu nhiên, nếu bạn sử dụng cách tiếp cận (Exception e), bạn sẽ biết các loại ngoại lệ khác nhau mà bạn có thể gặp phải. RuntimeWrappedException là thứ mà bất kỳ kiểu không ngoại lệ nào được quản lý sẽ được ánh xạ tới (đối với các ngôn ngữ có thể ném một chuỗi) và những ngôn ngữ khác sẽ được ánh xạ, chẳng hạn như OutOfMemoryException và AccessViolationException. COM Interop HRESULTS hoặc các ngoại lệ không phải E___FAIL sẽ ánh xạ tới COMException, và cuối cùng khi kết thúc, bạn có SEHException cho E_FAIL hoặc bất kỳ ngoại lệ chưa được ánh xạ nào khác.

Vậy bạn nên làm gì? Lựa chọn tốt nhất là đừng ném các ngoại lệ khỏi mã chưa được quản lý của bạn! Hả. Thực sự, mặc dù nếu bạn có quyền lựa chọn, hãy đặt ra các rào cản và thất bại khiến lựa chọn nào trở nên tồi tệ hơn, khả năng bị rò rỉ bộ nhớ trong quá trình xử lý ngoại lệ hoặc không biết loại ngoại lệ của bạn là gì.


-1

Một tiêu chuẩn thử bắt sẽ thực hiện thủ thuật mà tôi tin tưởng.

Tôi gặp phải sự cố tương tự với một ngoại lệ System.data ném một ngoại lệ sqlClient mà không có ý nghĩa, thêm một try..catch vào mã của tôi đã thực hiện thủ thuật trong trường hợp này


-2

Nếu bạn sử dụng một

try
{

}
catch(Exception ex)
{

}

nó sẽ bắt TẤT CẢ các ngoại lệ, tùy thuộc vào cách bạn gọi các thư viện bên ngoài, bạn có thể nhận được một ngoại lệ liên quan đến com đóng gói lỗi nhưng nó sẽ bắt lỗi.


Mặc dù vậy, bạn không thể bắt được StackOverflow hoặc OutOfMemoryException, đúng không?
core

đó là những lỗi kết thúc, tạm dừng ứng dụng, vì vậy bạn không thể làm việc với chúng.
Người bán Mitchel

7
Điều này thực sự không hoàn toàn chính xác, điều này sẽ bắt tất cả các trường hợp ngoại lệ tuân thủ CLS. C ++ / CLI và MC ++ đều là ngôn ngữ có khả năng loại bỏ các ngoại lệ không tuân thủ CLS.
Peter Oehlert

1
Tôi đồng ý với Peter, tôi đang làm việc với các DLL không được quản lý và tôi không thể nắm bắt một số ngoại lệ.
Tilendor

20
Câu hỏi này có 17 lượt ủng hộ và 7 lượt yêu thích tính đến thời điểm tôi viết nhận xét này, vì vậy đây rõ ràng là một vấn đề đang xảy ra với mọi người và tôi nghĩ mọi người sẽ thử một khối bắt đơn giản trước khi sử dụng SO. Cá nhân tôi đã thấy các ngoại lệ bùng nổ ngay thông qua cấu trúc bạn đề xuất khi chúng đến từ các phụ thuộc không được quản lý. Tôi không nghĩ câu trả lời này là chính xác.
JohnFx
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.