intTypePromotion=1
zunia.vn Tuyển sinh 2024 dành cho Gen-Z zunia.vn zunia.vn
ADSENSE

Những chủ đề tiến bộ trong C# Lỗi và xử lí biệt lệ - Phần 2

Chia sẻ: Nguyen Uyen | Ngày: | Loại File: PDF | Số trang:17

81
lượt xem
9
download
 
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Giả sử rằng người sử dụng gõ 1 số mà không nằm giữa 0 và 5 . điều này được đón bởi câu lệnh if và 1 đối tượng IndexOutOfRangeExceptionsẽ được khởi tạo và ném.vào lúc này máy tính sẽ ngay lập tức thoát khỏi khối try và tìm khối catch mà xử lí IndexOutOfRangeException. khối catch đầu tiên mà nó đến là khối này : catch (IndexOutOfRangeException e) { Console.WriteLine( "Exception: Number should be between 0 and 5." + e.Message); } ...

Chủ đề:
Lưu

Nội dung Text: Những chủ đề tiến bộ trong C# Lỗi và xử lí biệt lệ - Phần 2

  1. Những chủ đề tiến bộ trong C# Lỗi và xử lí biệt lệ - Phần 2 Giả sử rằng người sử dụng gõ 1 số mà không nằm giữa 0 và 5 . điều này được đón bởi câu lệnh if và 1 đối tượng IndexOutOfRangeExceptionsẽ được khởi tạo và ném.vào lúc này máy tính sẽ ngay lập tức thoát khỏi khối try và tìm khối catch mà xử lí IndexOutOfRangeException. khối catch đầu tiên mà nó đến là khối này : catch (IndexOutOfRangeException e) { Console.WriteLine( "Exception: Number should be between 0 and 5." + e.Message); }
  2. Bởi vì khối catch này lấy 1 thông số của một lớp tương đương , điều này sẽ được truyền qua 1 thể hiện của biệt lệ và thực thi.trong trường hợp này, chúng ta trình bày,1 thông báo lỗi và thuộc tính exception.message (đáp lại chuỗi mà chúng ta đã truyền đến hàm dựng của IndexOutOfRange).sau khi thực thi khối catch này , điều khiển chuyển đến khối finally, như là không có biệt lệ nào xuất hiện. Chú ý rằng chúng ta cũng cung cấp một khối catch khác : catch (Exception e) { Console.WriteLine("An exception was thrown. Message was: " + e.Message); } Khối catch này cũng có khả năng xử lý IndexOutOfRangeException nếu không có sự kiện rằng biệt lệ đã được đón bắt bởi khối catch trước- một sự tham chiếu đến 1 lớp cơ sở có thể cũng chuyển đến bất kỳ 1 thể hiện của mộ lớp dẫn xuất từ nó.và tất cả biệt lệ mà dẫn xuất từ system.exception . vậy tại sao khối catch này không được thực thi? câu trả lời là máy tính chỉ thực thi khối catch thích hợp đầu tiên mà nó tìm thấy. vậy tại sao khối catch thứ hai này lại nằm ở đây ? thật ra thì không chỉ đoạn mã của ta mới được bao phủ
  3. bởi khối try ,mà bên trong khối, chúng ta thực sự gọi những phương thức biệt nhau trong namspace system ( Console.ReadLine(), riêng Console.Write(), and Convert.ToInt32()), và bất kỳ phương thức nào trong đây cũng có thể ném ra một biệt lệ. Nếu chúng ta gõ một thứ gì không phải là số - say hoặc hello ,sau đó phương thức convert.toin32() sẽ ném ra một biệt lệ của lớp System.FormatException, để chỉ định chuỗi được truyền vào toin32() không nằm trong định dạng mà có thể chuyển thành kiểu int. khi điều này xảy ra, máy tính sẽ truy vết xuyên suốt phương thức gọi , tìm hàm xử lí mà có thể xử lí biệt lệ này. khối catch đầu tiên của chúng ta ( cái mà bắt IndexOutOfRangeException) sẽ không thực hiện.máy tính tìm đến cái thứ hai.cái này sẽ thi hành bởi vì FormatException là một dẫn xuất từ exception, vì vậy một thực thể FormatException có thể được truyền như là một thông số ở đây. Cấu trúc của ví dụ trên thực sự là kiểu tình huống đẹp với nhiều khối catch.chúng ta sẽ bắt đầu với khối catch được thiết kế để bẫy trạng thái lỗi cụ thể. sau đó, chúng ta hoàn thành với nhiều khối catch sẽ bao phủ bất kì lỗi nào mà chúng ta không viết những hàm xử lí lỗi cụ thể.việc sắp xếp các khối catch là quan trọng.nếu chúng ta viết tên 2 khối thứ tự ngược nhau , mã sẽ
  4. không phiên dịch bởi vì khối catch thứ hai sẽ không bao giờ có thể được tham chiếu đến ( khối catch exception có thể bắt tất cả các biệt lệ) Tuy nhiên chúng ta cũng nhìn vào khối catch thứ ba: catch { Console.WriteLine("Some other exception has occurred"); } Đây là khối catch chung cho tất cả - nó không nhận bất kì thông số nào . lý do của khối block này là bắt các biệt lệ được ném bởi những đoạn mã không được viết trong C#, hoặc thậm chí không được quản lí trong C#. như bạn thấy, đó là một sự đòi hỏi của ngôn ngữ C# mà chỉ thực thể của lớp được dẫn xuất từ system.exception mới có thể ném như một biệt lệ.nhưng những ngôn ngữ khác không có giới hạn này- ví dụ C++ cho phép bất kì một biến nào được ném như là một biệt lệ.nếu mã của ta gọi trong thư viện hay những tập hợp mà được viết trong những ngôn ngữ khác ,sau đó nó có thể t ìm một biệt lệ được ném mà không dẫn xuất từ system.exception , mặc dù trong nhiều trường hợp , cơ chế của .NET sẽ bẫy những biệt lệ này và chuyển chúng thành đối tượng biệt lệ .NET. tuy nhiên không có nhiều khối catch có
  5. thể làm điều này, bởi vì chúng ta không biết những lớp biệt lệ nào có thể trình bày . Bây giờ ta sẽ chạy đoạn mã ví dụ mà ta đả phân tích .minh họa cho những tình huống nhập khác nhau xảy ra.và cả việc IndexOutOfRangeException và FormatException được ném: SimpleExceptions Input a number between 0 and 5 (or just hit return to exit)> 4 Your number was 4 Thank you Input a number between 0 and 5 (or just hit return to exit)> 0 Your number was 0 Thank you Input a number between 0 and 5 (or just hit return to exit)> 10 Exception: Number should be between 0 and 5. You typed in 10 Thank you Input a number between 0 and 5 (or just hit return to exit)> hello An exception was thrown. Message was: Input string was not in a correct format. Thank you Input a number between 0 and 5 (or just hit return to exit)>
  6. Thank you Đón bắt những biệt lệ từ những các đoạn mã khác không nằm trong chương trình Ở ví dụ trước,ta đã họa hai biệt lệ.1 cái là minh IndexOutOfRangeException,được tung ra bởi mã của ta.cái còn lại, FormatException được tung ra từ bên trong của 1 torng những lớp cơ sở.ta thường gặp điều này.tuy nhiên các mã torng các thư viện hiếm khi bắt các biệt lệ, xem đó như là trách nhiệm của các mã client ( mã mà ta viết). Thông thường, ta sẽ tìm các biệt lệ được ném từ các thư viện lớp cơ sở khi ta vá lỗi. mục đích của ta là đảm bảo vào thời gian chạy của các chươn gtrình các biệt lệ thực sự chỉ xuất hiện vào lúc nào đó và nếu có teh63 thì được xử lí theo một cách nào đó theo ý của ta . Những thuộctính của system.exception Trong ví dụ trên chúng ta chỉ xem xét 1 thuộc tính đó là message, của đối tượng exception. tuy nhiên có 1 số những thuộc tính trong lớp system.exception - helplink: 1 liên kết đến 1 tập tin trợ giúp mà cung cấp nhiều thông tin hơn về biệt lệ - message: chuỗi mô tả trạng thái lỗi
  7. - source : tên của ứng dụng hoặc đối tượng mà gây ra lỗi - Stacktrace: chi tiết về phương thức gọi stack ( để giúp đỡ truy dấu vết phương thức mà ném ra biệt lệ) - TargetSite: một đối tượng phản ánh của .NET mà mô tả phương thức ném ra biệt lệ - InnerException :nếu biệt lệ này được ném từ bên trong một khối catch , nó chứa đựng đối tượng biệt lệ mà gửi đoạn mã vào trong khối catch. Trong những thuộc tính này , StackTrace và TargetSite được cung cấp tự động bởi thời gian chạy .NET nếu dấu vết Stack có giá trị. Source luôn luôn được điền bởi thời gian chạy .NET như là tên của tập hợp, mà biệt lệ đuợc phát ra. Trong khi đó message ,helplink,innerexception phải được điền bởi mã mà ném ra biệt lệ, bằng việc thiết lập những thuộc tính này ngay trước Khi ném ra biệt lệ,do đó trong ví dụ mã để ném biệt lệ có thể là : if (ErrorCondition == true) { Exception myException = new ClassmyException("Help!!!!"); myException.Source = "My Application Name"; myException.HelpLink = "MyHelpFile.txt"; throw myException;
  8. } Điều gì xảy ra nêu biệt lệ không được xử lí Thỉnh thoảng 1 biệt lệ được tung ra , nhưng không có một khối catch nào trong mã có thể xử lí loại biệt lệ này. ví dụ SimpleExceptions cho thấy điều này .giả sử trong ví dụ chúng ta bỏ qua FormatException và những khối bắt tất cả và chỉ cung cấp một khối mà bẩy lỗi catch IndexOutOfRangeException.trong tình huống này điều gì xảy ra khi 1 FormatException được tung ra? câu trả lời là thời gian chạy .NET sẽ bắt nó. Sau đó trong phần này chúng ta sẽ xem làm thế nào nó có thể lồng những khối try , và quả thật trong ví dụ đã có sẵn khối try được lồng phiá sau chương trình .thời gian chạy .NET đặ toàn bộ chương trình của bạn trong 1 khối try khổng lồ- điều này được làm trong mỗi chương trình .NET.khối try này có một hàm xử lí catch mà có thể bắt bất kỳ kiểu biệt lệ nào.nếu biệt lệ trong mã không được xử lí ,thì nó sẽ truyền ra cho thời gian chạy .NET đón bắt . tuy nhiên kết quả sẽ không như bạn muốn , nghĩa là chương trình của bạn có thể bị ngắt và người sử dụng sẽ nhìn thấy thông báo phàn nàn mã của bạn đã không xử lí biệt lệ thêm vào đó là những thông tin mà .NET nhận đuợc.tuy nhiên ít nhất thì biệt lệ cũng đã được đón bắt. Lồng những khối try
  9. Một đặc tính tốt của biệt lệ là có thể lồng những khối try trong những khối try khác ví dụ như : try { // Point A try { // Point B } catch { // Point C } finally { // Dọn dẹp } // Point D
  10. } catch { // xử lí lỗi } finally { // dọn dẹp } Nếu biệt lệ được tung ra bên trong khối try ngoài nhưng bên ngoài khối try bên trong (điểm a và d), thì tình huống sẽ giống như bạn đã được học trước đây. Nếu biệt lệ đưọc ném bên trong khối try ( điểm B) có một khối catch thích hợp để xử lí biệt lệ này, thì biệt lệ được xử lí ở đó và khối finally bên trong được thực thi trước khi việc thực thi tiếp tục bên trong của khối try nằm ngoài ( điểm D) bây giờ giả sử một biệt lệ xuất hiện bên trong khối try trong và không có khối catch trong để xử lí . lúc này khối finally trong được thực thi, nhưng
  11. sau đó thời gian chạy .NET sẽ không có chọn lựa nào khác là rời khỏi toàn bộ khối try này và tìm kiếm hàm xử lí biệt lệ thích hợp ở nơi tiếp theo là khối catch ngoài. nếu tìm được thì xử lí và nhảy dến khối finally ngoài.nếu không thấy thì tìm tiếp tục,nếu vẫn không thấy thì khối finally ngoài sẽ thi hành sau đó sẽ chuyển cho thời gian chạy .NET. Một điểm thú vị nữa nếu một biệt lệ tung ra ở điểm C. nếu chương trình ở điểm C thì nó phải xử lí một biệt lệ được ném ở điểm B.điều này là hợp pháp khi ném một biệt lệ khác từ bên trong của 1 khối catch,trong trường hợp này , biệt lệ được đối xử như là nó được ném bởi khối try ngoài.và thực thi khối finally trong, trước khi khối catch ngoài xử lí.nếu 1 biệt lệ được ném từ khối finally trong , điều khiển sẽ lập tức chuyển đến hàm xử lí tương đương tốt nhất, với việc tìm kiếm bắt đầu ở khối catch ngoài. Quan trọng : việc ném biệt lệ từ khối catch hay finally là hợp lệ Chúng ta đã biết được làm thế nào các khối try lồng nhau làm việc . sau đây chúng ta tìm hiểu xem tại sao chúng ta phải làm điều đó ? có 2 lí do : - Để cập nhật kiểu biệt lệ được ném - Cho phép kiểu biệt lệ khác nhau được xử lí ở nơi khác nhau trong mã cuả bạn. Cập nhật kiểu biệt lệ
  12. Điều này hữu ích khi kiểu biệt lệ được ném ra không mô tả đầy đủ vấn đề. Xử lí những biệt lệt khác nhau ở những nơi khác nhau Lý do thứ hai để lồng những khối try là để những kiểu biệt lệ khác nhau có thể xử lí ở những vị trí khác nhau trong mã của bạn. Một ví dụ hay cho điều này là nếu bạn có một vòng lặp nơi mà các trạng thái biệt lệ khác nhau có thể xuất hiện, một vài trong số chúng nghiêm trọng đủ để bạn cần phải bỏ ra khỏi vòng lặp.trong khi những cái khác ít nghiêm trọng hơn đơn giản đòi hỏi bạn bỏ phần lặp này và di chuyển đến phần lặp khác trong vòng lặp của bạn.bạn có thể làm điều này bằng cách cài khối try bên trong vòng lặp mà xử lí những lỗi không nghiêm trọng,và một khối try ở ngoài xử lí những lỗi nghiêm trọng. Những lớp biệt lệ do người sử dụng định nghĩa. Trong ví dụ sau, gọi là MortimerColdCall sẽ chứa đựng 2 khối try lồng nhau, và cũng minh họa thực tập việc định nghĩa lớp biệt lệ tuỳ biến của riêng ta.và tung một biệt lệ khác từ bên trong một khối try Trong ví dụ này ,ta sẽ làm quen với công ty điện thoại di động mortimer phones ( phụ lục A).giả sử rằng công ty muốn có thêm khách hàng. đội kinh doanh của cty sắp đưa ra danh sách của những người được mời trở thành khách hàng hoặc để dùng cho kinh doanh. để làm điều này ta có một tập tin
  13. lưu tên của những người được gọi.tập tin nên được định dạng chuẩn mà dòng đầu tiên chứa số người trong tập tin,và mỗi dòng tiếp theo chứa đựng tên của người kế tiếp. ví dụ : 4 Avon from 'Blake's 7' Zbigniew Harlequin Simon Robinson Christian Peak Chương trình của ta sẽ hỏi người sử dụng tên tập tin : đơn giản đọc nó và trình bày tên trong tập tin. nghe có vẻ đơn giản nhưng có một vài lỗi có thể xảy ra: Tên tập tin không tồn tại .biệt lệ FileNotFound sẽ tung ra tập tin có thể định dạng không đúng.có 2 vấn đề có thể có : thứ nhất: dòng đầu tiên không phải là một số nguyên. Thứ hai :số tên không khớp với số nguyên ở dòng đầu.để giải quyết vấn đề này chúng ta phải tự xây dựng lấy lớp biệt lệ , ở đây ta đặt tên là ColdCallFileFormatException Cũng có những vấn đề khác tuy nhiên không nghiêm trọng , chúng ta có thể sử dụng các khối try bên trong .ví dụ nếu là người gián điệp của công ty khác ( chử cái đầu là Z) thì chúng ta có thể bỏ qua người đó và xử lí ngưòi
  14. kế tiếp. biệt lệ này được gọi là LandLineSpyFoundException , tất nhiên đây là một đối tuợng biệt lệ tuỳ biến khác. cuối cùng chúng ta sẽ thực thi ví dụ này bằng việc soạn 1 lớp,ColdCallFileReader, mà duy trì việc nối giữa tập tin goị-lạnh ( cold-call ) và xuất dữ liệu từ nó.chúng ta soạn mã này theo cách an toàn , nghĩa là những phương thức của nó sẽ ném các biệt lệ nếu chúng được gọi không hợp lí, ví dụ nếu phương thức đọc tập tin đưọc gọi trước phương thức mở tập tin .để xử lí điều này ta soạn ra một lớp biệt lệ khác : UnexpectedException. Đón bắt biệt lệ do người sử dụng định nghĩa : Chúng ta bắt đầu với phương thức main() trong ví dụ MortimerColdCall mà bắt những biệt lệ riêng của ta. using System; using System.IO; namespace Wrox.ProCSharp.AdvancedCSharp { class MainEntryPoint { static void Main() { string fileName;
  15. Console.Write("Please type in the name of the file " + "containing the names of the people to be cold-called > "); fileName = Console.ReadLine(); ColdCallFileReader peopleToRing = new ColdCallFileReader(); try { peopleToRing.Open(fileName); for (int i=0 ; i
  16. "The file {0} appears to have been corrupted", fileName); Console.WriteLine("Details of problem are: {0}", e.Message); if (e.InnerException != null) Console.WriteLine( "Inner exception was: {0}", e.InnerException.Message); } catch(Exception e) { Console.WriteLine("Exception occurred:\n" + e.Message); } finally { peopleToRing.Dispose(); } Console.ReadLine(); } } Trong khối try ta mở file ( phương thức ColdCallFileReader.Open() ) và lặp tất cả tên trong đó.phương thức ColdCallFileReader.ProcessNextPerson()
  17. đọc và trình bày tên của người kế tiếp trong tập tin.trong khi thuộc tính ColdCallFileReader.NPeopleToRing bảo cho ta biết bao nhiêu người nên có trong tập tin ( bằng cách đọc dòng đầu tiên ) có 3 khối catch : FileNotFoundException and ColdCallFileFormatException và 1 khối catch bẫy bất kì biệt lệ .NET nào. biệt lệ FileNotFoundException đơn giản trình bày một thông điệp của riêng ta biệt lệ ColdCallFileFormatException trình bày chi tiết hơn bao gồm chi tiết về biệt lệ bên trong nếu có,với đầy đủ thông tin kĩ thuật . Cuối cùng ,nếu có bất kì biệt lệ khác 2 biệt lệ trên ta sẽ đón bắt bằng khối catch exception .thay vì để cho thời gian chạy .NET xử lí . Khối finally sẽ dọn dẹp tài nguyên , trong trường hợp này là đóng tập tin bằng phương thức ColdCallFileReader.Dispose()
ADSENSE

CÓ THỂ BẠN MUỐN DOWNLOAD

 

Đồng bộ tài khoản
2=>2