Làm thế nào để ghi lại các ngoại lệ được ném trong c # /. Net


139

Tôi hiện đang viết một khung nhỏ sẽ được sử dụng nội bộ bởi các nhà phát triển khác trong công ty.

Tôi muốn cung cấp thông tin Intellisense tốt, nhưng tôi không chắc làm thế nào để ghi lại các trường hợp ngoại lệ.

Trong ví dụ sau:

public void MyMethod1()
{
    MyMethod2();

    // also may throw InvalidOperationException
}

public void MyMethod2()
{
    System.IO.File.Open(somepath...); // this may throw FileNotFoundException

    // also may throw DivideByZeroException
}

Tôi biết đánh dấu cho các tài liệu ngoại lệ là:

/// <exception cref="SomeException">when things go wrong.</exception>

Điều tôi không hiểu là làm thế nào để ghi lại các trường hợp ngoại lệ được ném bởi mã được gọi bởi MyMethod1() ?

  • Tôi có nên ghi lại các trường hợp ngoại lệ MyMethod2()
  • Tôi có nên ghi lại các trường hợp ngoại lệ File.Open()?

Điều gì sẽ là cách tốt nhất để ghi lại các trường hợp ngoại lệ có thể?


4
Tôi biết đây không phải là chính xác những gì bạn đã hỏi (và đây là một câu hỏi thực sự cũ) nhưng Eric Lippert (nhà phát triển chính trên trình biên dịch và nhóm thiết kế microsoft C #) đã viết một bài đăng trên blog về 4 loại ngoại lệ mà tôi nghĩ mọi nhà phát triển nên suy nghĩ về thời gian xử lý văn bản ngoại lệ mã: blogs.msdn.com/b/ericlippert/archive/2008/09/10/...
javajavajavajavajava

@javajavajavajavajava Cảm ơn liên kết - chắc chắn đáng đọc.
Arnold Zokas

Tôi nghĩ rằng đây là một câu hỏi hợp lệ vì hoàn toàn không rõ ràng về cách ghi lại các trường hợp ngoại lệ trong C # và các quan điểm 50K cho thấy nó cũng không rõ ràng đối với nhiều người. Câu trả lời được bình chọn nhiều thứ hai là rất hữu ích vì nó cho thấy sử dụng xmldocs hiện có để ghi lại điều này. Bỏ phiếu để mở lại. Lý do gần gũi "dựa trên quan điểm" này đang giết chết rất nhiều câu hỏi lập trình thực sự rất hữu ích.
Alexei

Câu trả lời:


110

Bạn nên ghi lại mọi ngoại lệ có thể được ném bởi mã của bạn, bao gồm cả các ngoại lệ trong bất kỳ phương thức nào bạn có thể gọi.

Nếu danh sách trở nên hơi lớn, bạn có thể muốn tạo loại ngoại lệ của riêng mình. Nắm bắt tất cả những gì bạn có thể gặp trong phương pháp của bạn, bọc chúng trong ngoại lệ của bạn và ném nó.

Một nơi khác mà bạn có thể muốn làm theo cách này là nếu phương thức của bạn nằm trên mặt API của bạn. Giống như mặt tiền đơn giản hóa nhiều giao diện thành một giao diện, API của bạn sẽ đơn giản hóa nhiều ngoại lệ thành một ngoại lệ duy nhất. Làm cho việc sử dụng mã của bạn dễ dàng hơn cho người gọi.


Để trả lời một số mối quan tâm của Andrew (từ các bình luận), có ba loại ngoại lệ: Những người bạn không biết, những người bạn biết và không thể làm gì, và những gì bạn biết và có thể làm gì đó.

Những người bạn không biết về bạn muốn cho đi. Đó là nguyên nhân của sự thất bại nhanh chóng - tốt hơn là ứng dụng của bạn gặp sự cố hơn là vào trạng thái mà bạn có thể sẽ làm hỏng dữ liệu của mình. Sự cố sẽ cho bạn biết về những gì đã xảy ra và tại sao, điều này có thể giúp loại bỏ ngoại lệ đó ra khỏi danh sách "những điều bạn không biết về".

Những cái bạn biết và không thể làm gì là những ngoại lệ như OutOfMemoryExceptions. Trong trường hợp cực đoan, bạn có thể muốn xử lý các trường hợp ngoại lệ như thế này, nhưng trừ khi bạn có một số yêu cầu khá đáng chú ý, bạn coi chúng như thể loại đầu tiên - hãy đi. Bạn phải ghi lại những trường hợp ngoại lệ này? Bạn sẽ trông khá ngu ngốc khi ghi lại các OOM trên mỗi phương thức mới tạo ra một đối tượng.

Những cái bạn biết và có thể làm một cái gì đó là những cái bạn nên ghi chép và gói lại.

Bạn có thể tìm thấy một số hướng dẫn thêm về xử lý ngoại lệ ở đây.


3
Tôi phải thừa nhận điều này không có vẻ rất thực tế. Tôi không thể tưởng tượng có bao nhiêu ngoại lệ tiềm năng có thể được ném bởi bất kỳ mã nào tôi có thể gọi, cộng với đó là những thứ như OutOfMemoryException mà bạn không muốn bắt và bọc.
Andrew Hare

3
Câu trả lời của bạn có tốt không, nhưng thực ra đó là hai câu trả lời trái ngược nhau. "ghi lại mọi ngoại lệ có thể bị ném bởi mã của bạn" và "Những cái bạn biết và có thể làm gì đó là những thứ bạn nên ghi lại".
tymtam

2
@Tymek: Không. Nửa đầu đã trả lời câu hỏi "làm thế nào tôi nên ghi lại các trường hợp ngoại lệ", phần thứ hai chỉ ra câu trả lời rõ ràng rõ ràng cho "những trường hợp ngoại lệ nào tôi nên ghi lại." Điều đầu tiên không ngụ ý rằng bạn ghi lại mọi ngoại lệ có thể xảy ra. Một số người quá nghĩa đen, đòi hỏi nửa thứ hai.

5
@Tymek Tôi nghĩ rằng quan điểm của bạn có thể là nếu bạn có thể làm điều gì đó về nó, tại sao không làm điều gì đó về nó thay vì suy nghĩ lại và ghi lại nó? Có thể sẽ khôn ngoan hơn khi nói "Những người bạn biết về mã khách hàng có thể làm gì đó". Điều này loại bỏ mâu thuẫn, bởi vì đây là những ngoại lệ lý tưởng cho tài liệu.
mo.

Đối với các trường hợp ngoại lệ bạn 'buông tay', bạn luôn có thể bắt chúng ở cấp độ thấp hơn ghi nhật ký chúng hoặc một cái gì đó. Bạn biết; chỉ làm cho một cách thân thiện với người dùng để cho chương trình sụp đổ.
Nyerguds

96

Bạn nên sử dụng tài liệu xml tiêu chuẩn .

/// <exception cref="InvalidOperationException">Why it's thrown.</exception>
/// <exception cref="FileNotFoundException">Why it's thrown.</exception>
/// <exception cref="DivideByZeroException">Why it's thrown.</exception>
public void MyMethod1()
{
    MyMethod2();
    // ... other stuff here
}

/// <exception cref="FileNotFoundException">Why it's thrown.</exception>
/// <exception cref="DivideByZeroException">Why it's thrown.</exception>
public void MyMethod2()
{
    System.IO.File.Open(somepath...);
}

/// <exception cref="FileNotFoundException">Why it's thrown.</exception>
public void MyMethod3()
{
    try
    {
        MyMethod2();
    }
    catch (DivideByZeroException ex)
    {
        Trace.Warning("We tried to divide by zero, but we can continue.");
    }
}

Giá trị khi thực hiện theo cách này là bạn đang cung cấp tài liệu về các ngoại lệ đã biết có thể xảy ra. Tài liệu này có sẵn trong intellisense nếu bạn đang sử dụng phòng thu trực quan và có thể nhắc nhở bạn (hoặc những người khác) sau về các trường hợp ngoại lệ mà bạn có thể mong đợi.

Bạn muốn chỉ định các loại ngoại lệ cụ thể, bởi vì bạn có thể xử lý một loại ngoại lệ, trong khi các loại khác là kết quả của một vấn đề nghiêm trọng và không thể sửa được.


1
Làm thế nào là thêm bất kỳ giá trị? Ví dụ, tất cả các ngoại lệ này là dẫn xuất của loại Ngoại lệ. Theo kinh nghiệm của tôi, sẽ không thực tế khi nghĩ đến mọi loại ngoại lệ khác có thể được ném từ các API khác được gọi trong các phương thức của bạn. Quan điểm của tôi là, chúng ta không nên lo lắng về bất kỳ ngoại lệ nào được ném ra từ một phương thức so với những phương pháp mang bất kỳ thông tin Kinh doanh nào.
Illuminati

7
@ShiranGinige kinh nghiệm của bạn là sai.
Grozz

35

Bạn có thể làm cho quy trình tài liệu của mình dễ dàng hơn bằng cách sử dụng một số bổ trợ tuyệt vời. Một trong số đó là GhostDoc , một bổ trợ miễn phí cho Visual Studio, tạo ra các bình luận XML-doc. Ngoài ra, nếu bạn sử dụng ReSharper , hãy xem Plugin Agent Johnson tuyệt vời cho ReSharper, bổ sung một tùy chọn để tạo nhận xét XML cho các ngoại lệ bị ném.

Cập nhật: Có vẻ như Agen Johnson không có sẵn cho R # 8, thanh toán Đặc biệt cho ReSharper như một thay thế ...

Bước 1: GhostDoc tạo nhận xét XML (Ctrl-Shift-D), trong khi plugin Agent Johnson cho ReSharper cũng đề xuất ghi lại ngoại lệ:

bước 1

Bước 2: Sử dụng phím tắt của ReSharper (Alt-Enter) để thêm tài liệu ngoại lệ:

bước 2 http://i41.tinypic.com/osdhm

Mong rằng sẽ giúp :)


Các liên kết tinypic bị hỏng.
ANeves

11

Theo những gì tôi hiểu, ý định sử dụng phần tử <ngoại lệ> là sử dụng nó khi phương thức trang trí, không phải là ngoại lệ:

/// <summary>Does something!</summary>
/// <exception cref="DidNothingException">Thrown if nothing is actually done.</exception>
public void DoSomething()
{
// There be logic here
}

Các ngoại lệ có thể được ném bởi các phương thức khác được gọi nên được bắt, xử lý và ghi lại trong các phương thức đó. Các ngoại lệ có thể có thể được ném bởi .NET hoặc các ngoại lệ được ném rõ ràng bằng mã của riêng bạn nên được ghi lại.

Theo như có bất kỳ cụ thể hơn thế, có lẽ bạn có thể nắm bắt và ném ngoại lệ tùy chỉnh của riêng bạn?


4

Một phần của hợp đồng cho phương pháp của bạn nên kiểm tra xem các điều kiện trước có hợp lệ không, vì vậy:

public void MyMethod2()
{
    System.IO.File.Open(somepath...); // this may throw FileNotFoundException
}

trở thành

/// <exception cref="FileNotFoundException">Thrown when somepath isn't a real file.</exception>
public void MyMethod2()
{
    FileInfo fi = new FileInfo( somepath );
    if( !fi.Exists )
    {
        throw new FileNotFoundException("somepath doesn't exists")
    }
    // Maybe go on to check you have permissions to read from it.

    System.IO.File.Open(somepath...); // this may still throw FileNotFoundException though
}

Với phương pháp này, việc ghi lại tất cả các trường hợp ngoại lệ mà bạn ném một cách rõ ràng mà không cần phải ghi lại rằng OutOfMemoryException thể bị ném, v.v.


1
Không chắc chắn điểm của kiểm tra đó là gì nếu bạn sẽ nhân đôi ngoại lệ rằng Opencuộc gọi sẽ ném bất kỳ cách nào (không đề cập, như bạn lưu ý, rằng có một cuộc đua và kiểm tra không đảm bảo thành công Open) .. .
Matt Enright

1
@MattEnright Được cấp, nhưng tôi đã thực hiện điều này một chút giả định để minh họa điểm ...
Rowland Shaw

1

Bạn nên ghi lại tất cả các trường hợp ngoại lệ có thể được ném bằng phương pháp của bạn.

Để ẩn chi tiết triển khai, tôi sẽ cố gắng tự xử lý một số ngoại lệ từ MyMethod2.

Bạn có thể xem xét việc gửi lại chúng, nếu bạn không thể xử lý hoặc giải quyết ngoại lệ. Chủ yếu được đóng gói / bọc trong một ngoại lệ có ý nghĩa hơn cho người gọi.


1

Thật vậy, như đã được trả lời, cách để ghi lại các trường hợp ngoại lệ là sử dụng Nhận xét XML.

Ngoài các plugin, bạn cũng có thể sử dụng các công cụ phân tích tĩnh có thể được tích hợp với TFS để đảm bảo bạn có các ngoại lệ được ghi lại.

Trong các liên kết bên dưới, bạn có thể thấy cách xây dựng quy tắc tùy chỉnh cho StyleCop để xác thực các ngoại lệ được ném bởi các phương thức của bạn đang được ghi lại.

http://www.josefcobonnin.com/post/2009/01/11/Xml-Documentation-Comments-Exceptions-I.aspx http://www.josefcobonnin.com/post/2009/01/15/Xml-Documentation -Comments-Exceptions-II.aspx

Trân trọng.


0

Tài liệu ngoại lệ dự kiến ​​trong phương thức của bạn, trong ví dụ của bạn tôi sẽ cho người dùng biết rằng phương pháp đó có thể ném một tệp không tìm thấy ngoại lệ.

Hãy nhớ rằng đó là thông báo cho người gọi về những gì mong đợi để họ có thể chọn cách đối phó với nó.

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.