Bất cứ thứ gì bên trong cuối cùng cũng được thực thi (hầu như) luôn luôn, vậy sự khác biệt giữa việc đặt mã vào nó hoặc không được tiết lộ là gì?
Bất cứ thứ gì bên trong cuối cùng cũng được thực thi (hầu như) luôn luôn, vậy sự khác biệt giữa việc đặt mã vào nó hoặc không được tiết lộ là gì?
Câu trả lời:
Mã bên trong một khối cuối cùng sẽ được thực thi bất kể có hay không có ngoại lệ. Điều này rất hữu ích khi nói đến một số chức năng vệ sinh nhất định mà bạn cần luôn luôn chạy như đóng các kết nối.
Bây giờ, tôi đoán câu hỏi của bạn là tại sao bạn nên làm điều này:
try
{
doSomething();
}
catch
{
catchSomething();
}
finally
{
alwaysDoThis();
}
Khi bạn có thể làm điều này:
try
{
doSomething();
}
catch
{
catchSomething();
}
alwaysDoThis();
Câu trả lời là rất nhiều lần mã bên trong câu lệnh bắt của bạn sẽ lấy lại một ngoại lệ hoặc thoát ra khỏi hàm hiện tại. Với mã sau, "alwaysDo This ();" cuộc gọi sẽ không được thực thi nếu mã bên trong câu lệnh bắt gặp trả lại hoặc ném ngoại lệ mới.
Hầu hết các lợi ích của việc sử dụng thử - cuối cùng đã được chỉ ra, nhưng tôi nghĩ tôi đã thêm cái này:
try
{
// Code here that might throw an exception...
if (arbitraryCondition)
{
return true;
}
// Code here that might throw an exception...
}
finally
{
// Code here gets executed regardless of whether "return true;" was called within the try block (i.e. regardless of the value of arbitraryCondition).
}
Hành vi này làm cho nó rất hữu ích trong các tình huống khác nhau, đặc biệt là khi bạn cần thực hiện dọn dẹp (xử lý tài nguyên), mặc dù một khối sử dụng thường tốt hơn trong trường hợp này.
bất cứ khi nào bạn sử dụng các yêu cầu mã không được quản lý như trình đọc luồng, yêu cầu db, v.v; và bạn muốn bắt ngoại lệ, sau đó sử dụng thử bắt cuối cùng và đóng luồng, trình đọc dữ liệu, v.v ... cuối cùng, nếu bạn không gặp lỗi khi kết nối không bị đóng, điều này thực sự tồi tệ với các yêu cầu db
SqlConnection myConn = new SqlConnection("Connectionstring");
try
{
myConn.Open();
//make na DB Request
}
catch (Exception DBException)
{
//do somehting with exception
}
finally
{
myConn.Close();
myConn.Dispose();
}
nếu bạn không muốn bắt lỗi thì hãy sử dụng
using (SqlConnection myConn = new SqlConnection("Connectionstring"))
{
myConn.Open();
//make na DB Request
myConn.Close();
}
và đối tượng kết nối sẽ được xử lý tự động nếu có lỗi, nhưng bạn không nắm bắt được lỗi
Bởi vì cuối cùng sẽ được thực thi ngay cả khi bạn không xử lý một ngoại lệ trong khối bắt.
Cuối cùng các câu lệnh có thể thực thi ngay cả sau khi trả về.
private int myfun()
{
int a = 100; //any number
int b = 0;
try
{
a = (5 / b);
return a;
}
catch (Exception ex)
{
Response.Write(ex.Message);
return a;
}
// Response.Write("Statement after return before finally"); -->this will give error "Syntax error, 'try' expected"
finally
{
Response.Write("Statement after return in finally"); // --> This will execute , even after having return code above
}
Response.Write("Statement after return after finally"); // -->Unreachable code
}
finally
, như trong:
try {
// do something risky
} catch (Exception ex) {
// handle an exception
} finally {
// do any required cleanup
}
là một cơ hội được đảm bảo để thực thi mã sau try..catch
khối , bất kể khối thử của bạn có ném ngoại lệ hay không.
Điều đó làm cho nó hoàn hảo cho những thứ như giải phóng tài nguyên, kết nối db, xử lý tệp, v.v.
tôi sẽ giải thích việc sử dụng cuối cùng với một ngoại lệ đọc tập tin Ví dụ
try{ StreamReader strReader = new StreamReader(@"C:\Ariven\Project\Data.txt"); Console.WriteLine(strReader.ReadeToEnd()); StreamReader.Close(); } catch (Exception ex) { Console.WriteLine(ex.Message); }
trong ví dụ trên nếu tệp có tên Data.txt bị thiếu, một ngoại lệ sẽ được ném và sẽ được xử lý nhưng câu lệnh được gọi StreamReader.Close();
sẽ không bao giờ được thực thi.
Bởi vì tài nguyên này liên quan đến độc giả không bao giờ được phát hành.
StreamReader strReader = null; try{ strReader = new StreamReader(@"C:\Ariven\Project\Data.txt"); Console.WriteLine(strReader.ReadeToEnd()); } catch (Exception ex){ Console.WriteLine(ex.Message); } finally{ if (strReader != null){ StreamReader.Close(); } }
Chúc mừng mã hóa :)
Lưu ý: "@" được sử dụng để tạo một chuỗi nguyên văn , để tránh lỗi "Trình tự thoát không được nhận dạng". Biểu tượng @ có nghĩa là đọc chuỗi đó theo nghĩa đen và không diễn giải các ký tự điều khiển khác.
Giả sử bạn cần đặt con trỏ trở về con trỏ mặc định thay vì con trỏ chờ (đồng hồ cát). Nếu một ngoại lệ được ném ra trước khi đặt con trỏ và không làm hỏng ứng dụng, bạn có thể bị bỏ lại với một con trỏ khó hiểu.
Đôi khi bạn không muốn xử lý một ngoại lệ (không có khối bắt), nhưng bạn muốn một số mã dọn dẹp thực thi.
Ví dụ:
try
{
// exception (or not)
}
finally
{
// clean up always
}
Khối cuối cùng có giá trị để dọn sạch mọi tài nguyên được phân bổ trong khối thử cũng như chạy bất kỳ mã nào phải thực thi ngay cả khi có ngoại lệ. Kiểm soát luôn được chuyển đến khối cuối cùng bất kể khối thoát thử như thế nào.
À ... tôi nghĩ tôi thấy những gì bạn đang nói! Mất tôi một giây ... bạn đang tự hỏi "tại sao lại đặt nó vào khối cuối cùng thay vì sau khối cuối cùng và hoàn toàn nằm ngoài thử-bắt-cuối".
Ví dụ, có thể là do bạn đang tạm dừng thực thi nếu bạn gặp lỗi, nhưng bạn vẫn muốn dọn sạch các tài nguyên, chẳng hạn như mở tệp, kết nối cơ sở dữ liệu, v.v.
Luồng điều khiển của Khối cuối cùng là sau khối Thử hoặc Bắt.
[1. First Code]
[2. Try]
[3. Catch]
[4. Finally]
[5. After Code]
với Ngoại lệ 1> 2> 3> 4> 5 nếu 3 có câu lệnh Trả về 1> 2> 3> 4
không có ngoại lệ 1> 2> 4> 5 nếu 2 có câu lệnh return 1> 2> 4
Như đã đề cập trong tài liệu :
Một cách sử dụng phổ biến của việc bắt và cuối cùng là cùng nhau để có được và sử dụng tài nguyên trong khối thử, xử lý các trường hợp đặc biệt trong khối bắt và giải phóng tài nguyên trong khối cuối cùng.
Nó cũng đáng đọc điều này , trong đó nêu rõ:
Khi một mệnh đề bắt phù hợp được tìm thấy, hệ thống chuẩn bị chuyển điều khiển sang câu lệnh đầu tiên của mệnh đề bắt. Trước khi thực hiện mệnh đề bắt đầu, hệ thống trước tiên thực hiện, theo thứ tự, bất kỳ mệnh đề cuối cùng nào được liên kết với các câu lệnh thử được lồng nhiều hơn so với mệnh đề bắt ngoại lệ.
Vì vậy, rõ ràng mã nằm trong finally
mệnh đề sẽ được thực thi ngay cả khi catch
mệnh đề trước có return
câu lệnh.