Vấn đề lưu trữ lỗi khi muốn "bắt" lỗi của VBA ?

Liên hệ QC

Nguyen Rem

Tất cả chỉ là đưa ra quyết định đúng đắn
Tham gia
23/2/22
Bài viết
211
Được thích
30
Giới tính
Nữ
Em chào các anh chị ^^ . Em hiện tại có một số chỗ chưa thực sự hiểu khi viết code! Mong cách anh chị cùng em giải thích và khắc phục lỗi

Vấn đề:
Theo em được biết thì Bộ nhớ của VBA chỉ có thể chứa được một lỗi duy nhất . Để kiểm chứng điều này thì hiện tại trong module 5 của em có một Sub sau: ( Các anh chị nhấn F8 để cho chạy từng dòng code)
1654868357301.png
Theo như em hiểu thì lúc gặp lỗi thứ nhất (Y = 20/0) , chương trình bỏ qua lỗi này và chạy đến sau ErrMsg: để chạy tiếp (Lỗi này đã được lưu vào bộ nhớ VBA) . Sau đó đến lúc gặp lỗi thứ hai(B = Sqr("abc")) mặc dù chỗ bôi vàng đã dùng để bỏ qua lỗi nhưng mà lỗi vẫn xuất hiện . Điều này là do bộ nhớ đã tồn tại một lỗi rồi ==> Không thể bỏ qua được nữa . Lý thuyết đúng .

Ở module 4 : Ta lại có một Sub sau (cái chỗ bôi đỏ là lỗi do thêm item trùng nhau vào một collection -Cố ý! Mục đích là để tìm giá trị bị trùng nhau- )
1654868956614.png
Chắc đến đây các anh cũng hiểu ý em nói là gì !
Cái chỗ bôi vàng là để bỏ qua lỗi nhưng khi vào vòng lặp For thì lỗi khi thêm item trùng vào collection là rất nhiều (Mâu thuẫn với giả thiết ở trên đưa ra - Bộ nhớ VBA chỉ lưu một lỗi duy nhất-)
Câu hỏi:
Vậy những điều lập luận của em có sai ở đâu không? và tại sao ?
 

File đính kèm

  • Collection .xlsm
    26.7 KB · Đọc: 7
Em chào các anh chị ^^ . Em hiện tại có một số chỗ chưa thực sự hiểu khi viết code! Mong cách anh chị cùng em giải thích và khắc phục lỗi

Vấn đề:
Theo em được biết thì Bộ nhớ của VBA chỉ có thể chứa được một lỗi duy nhất . Để kiểm chứng điều này thì hiện tại trong module 5 của em có một Sub sau: ( Các anh chị nhấn F8 để cho chạy từng dòng code)
View attachment 277157
Theo như em hiểu thì lúc gặp lỗi thứ nhất (Y = 20/0) , chương trình bỏ qua lỗi này và chạy đến sau ErrMsg: để chạy tiếp (Lỗi này đã được lưu vào bộ nhớ VBA) . Sau đó đến lúc gặp lỗi thứ hai(B = Sqr("abc")) mặc dù chỗ bôi vàng đã dùng để bỏ qua lỗi nhưng mà lỗi vẫn xuất hiện . Điều này là do bộ nhớ đã tồn tại một lỗi rồi ==> Không thể bỏ qua được nữa . Lý thuyết đúng .
Không phải thế.

Bạn có
Mã:
Debug.Print "Encounter Error: " & Err.Number

Nhưng nếu bạn thêm thành
Mã:
Debug.Print "Encounter Error: " & Err.Number
Debug.Print "Encounter Error: " & Err.Description

Thì bạn sẽ có kết quả:

Encounter Error: 11
Encounter Error: Division by zero


Nếu sau Err.Clear bạn cũng có
Mã:
Debug.Print "Encounter Error: " & Err.Number 'Encounter Error: 11
Debug.Print "Encounter Error: " & Err.Description

thì kết quả là

Encounter Error: 0
Encounter Error:


Tức mọi thông tin về lỗi gần nhất đã bị xóa hết. Không có cách nào phục hồi được những thông tin về lỗi nữa.

Thế còn nguyên nhân tại sao khi gặp B = Sqr("abc") thì lại nhẩy ra cửa sổ báo lỗi mà không thầm lặng thực hiện dòng tiếp theo là Exit Sub?

Bạn phải biết là khi có On Error GoTo ErrMsg thì khi gặp lỗi sẽ có bước nhẩy tới Label ErrMsg. Bắt đầu từ đây là việc thực hiện procedure xử lý lỗi. Khi đang trong quá trình xử lý lỗi hiện hành thì On Error Resume Next không tác dụng. Nói nôm na là không thể triển khai việc xử lý lỗi mới khi chưa kết thúc việc xử lý lỗi hiện hành. Khi sảy ra lỗi trong cụm xử lý lỗi hiện hành (bắt đầu từ ErrMsg) thì việc xử lý lỗi tiếp theo này sẽ diễn ra như bình thường, tức xuất hiện cửa sổ thông báo lỗi. Để kết thúc việc xử lý lỗi hiện hành trong cụm xử lý lỗi hiện hành thì dùng On Error Goto -1. Dấu hiệu là việc xử lý lỗi hiện hành đã kết thúc.

Ta xét 2 trường hợp:
1. Trong procedure xử lý lỗi hiện hành, tức từ dòng ErrMsg trở đi ta dùng On Error Goto -1 để kết thúc việc xử lý lỗi đã xảy ra. Nhưng ta không thiết lập procedure xử lý lỗi cho lỗi sẽ sảy ra tiếp theo. Lúc này thì khi gặp lỗi tiếp theo thì code sẽ lại nhẩy tới ErrMsg được thiết lập trước đó ở On Error Goto ErrMsg.

Muốn mục sở thị thì thay Err.Clear bằng On Error GoTo -1, và xóa On Error Resume Next.
Tất nhiên trong trường hợp này thì code sẽ chạy tới ngày tận thế vì cứ thực hiện B = Sqr("abc") thì bị lỗi và nhẩy phải về ErrMsg, rồi sau đó lại gặp B = Sqr("abc") rồi lạy nhẩy về ErrMsg, cứ thế đến "muôn đời".

2. Trong procedure xử lý lỗi hiện hành, tức từ dòng ErrMsg trở đi ta dùng On Error Goto -1 để kết thúc việc xử lý lỗi đã xảy ra, và sau đó thiết lập việc xử lý lỗi mới cho lỗi có thể sảy ra tiếp theo. Muốn mục sở thị thì thay Err.Clear bằng On Error GoTo -1, và giữ nguyên On Error Resume Next. Lúc này thì dòng Exit Sub sẽ được thực thi.

Cũng có thể thay On Error Resume Next bằng On Error Goto ErrMsg2. Lúc này thì dòng Exit Sub không được thực thi mà dòng Debug.Print "Encounter Error: " & Err.Number (sau ErrMsg2) được thực thi với kết quả

Encounter Error: 13

Dùng On Error Goto -1 ngoài "cụm xử lý lỗi" thì chỉ có tác dụng như Err.Clear.

Ở module 4 : Ta lại có một Sub sau (cái chỗ bôi đỏ là lỗi do thêm item trùng nhau vào một collection -Cố ý! Mục đích là để tìm giá trị bị trùng nhau- )

Chắc đến đây các anh cũng hiểu ý em nói là gì !
Cái chỗ bôi vàng là để bỏ qua lỗi nhưng khi vào vòng lặp For thì lỗi khi thêm item trùng vào collection là rất nhiều (Mâu thuẫn với giả thiết ở trên đưa ra - Bộ nhớ VBA chỉ lưu một lỗi duy nhất-)
Câu hỏi:
Vậy những điều lập luận của em có sai ở đâu không? và tại sao ?

Kết quả

$A$13: R MCRAE
$A$17: PRINTERS
$A$19: THOMAS S
$A$21: MANNERS
$A$23: FRAMERS
$A$24: FREIGHT 4U

là đúng rồi còn gì. Err.Clear là xóa thông tin về lỗi vừa sảy ra. Còn cụm IF ... END IF được thực hiện vì đúng là có lỗi mởi sảy ra. Đâu có phải vì lỗi cũ?

Tất nhiên bạn có 2 lần kết quả vì bạn dùng Debug.Print 2 lần.
 
Lần chỉnh sửa cuối:
Upvote 0
Không phải thế.

Bạn có
Mã:
Debug.Print "Encounter Error: " & Err.Number

Nhưng nếu bạn thêm thành
Mã:
Debug.Print "Encounter Error: " & Err.Number
Debug.Print "Encounter Error: " & Err.Description

Thì bạn sẽ có kết quả:

Encounter Error: 11
Encounter Error: Division by zero


Nếu sau Err.Clear bạn cũng có
Mã:
Debug.Print "Encounter Error: " & Err.Number 'Encounter Error: 11
Debug.Print "Encounter Error: " & Err.Description

thì kết quả là

Encounter Error: 0
Encounter Error:


Tức mọi thông tin về lỗi gần nhất đã bị xóa hết. Không có cách nào phục hồi được những thông tin về lỗi nữa.

Thế còn nguyên nhân tại sao khi gặp B = Sqr("abc") thì lại nhẩy ra cửa sổ báo lỗi mà không thầm lặng thực hiện dòng tiếp theo là Exit Sub?

Bạn phải biết là khi có On Error GoTo ErrMsg thì khi gặp lỗi sẽ có bước nhẩy tới Label ErrMsg. Bắt đầu từ đây là việc thực hiện procedure xử lý lỗi. Khi đang trong quá trình xử lý lỗi hiện hành thì On Error Resume Next không tác dụng. Nói nôm na là không thể triển khai việc xử lý lỗi mới khi chưa kết thúc việc xử lý lỗi hiện hành. Khi sảy ra lỗi trong cụm xử lý lỗi hiện hành (bắt đầu từ ErrMsg) thì việc xử lý lỗi tiếp theo này sẽ diễn ra như bình thường, tức xuất hiện cửa sổ thông báo lỗi. Để kết thúc việc xử lý lỗi hiện hành trong cụm xử lý lỗi hiện hành thì dùng On Error Goto -1. Dấu hiệu là việc xử lý lỗi hiện hành đã kết thúc.

Ta xét 2 trường hợp:
1. Trong procedure xử lý lỗi hiện hành, tức từ dòng ErrMsg trở đi ta dùng On Error Goto -1 để kết thúc việc xử lý lỗi đã xảy ra. Nhưng ta không thiết lập procedure xử lý lỗi cho lỗi sẽ sảy ra tiếp theo. Lúc này thì khi gặp lỗi tiếp theo thì code sẽ lại nhẩy tới ErrMsg được thiết lập trước đó ở On Error Goto ErrMsg.

Muốn mục sở thị thì thay Err.Clear bằng On Error GoTo -1, và xóa On Error Resume Next.
Tất nhiên trong trường hợp này thì code sẽ chạy tới ngày tận thế vì cứ thực hiện B = Sqr("abc") thì bị lỗi và nhẩy phải về ErrMsg, rồi sau đó lại gặp B = Sqr("abc") rồi lạy nhẩy về ErrMsg, cứ thế đến "muôn đời".

2. Trong procedure xử lý lỗi hiện hành, tức từ dòng ErrMsg trở đi ta dùng On Error Goto -1 để kết thúc việc xử lý lỗi đã xảy ra, và sau đó thiết lập việc xử lý lỗi mới cho lỗi có thể sảy ra tiếp theo. Muốn mục sở thị thì thay Err.Clear bằng On Error GoTo -1, và giữ nguyên On Error Resume Next. Lúc này thì dòng Exit Sub sẽ được thực thi.

Cũng có thể thay On Error Resume Next bằng On Error Goto ErrMsg2. Lúc này thì dòng Exit Sub không được thực thi mà dòng Debug.Print "Encounter Error: " & Err.Number (sau ErrMsg2) được thực thi với kết quả

Encounter Error: 13

Dùng On Error Goto -1 ngoài "cụm xử lý lỗi" thì chỉ có tác dụng như Err.Clear.



Kết quả

$A$13: R MCRAE
$A$17: PRINTERS
$A$19: THOMAS S
$A$21: MANNERS
$A$23: FRAMERS
$A$24: FREIGHT 4U

là đúng rồi còn gì. Err.Clear là xóa thông tin về lỗi vừa sảy ra. Còn cụm IF ... END IF được thực hiện vì đúng là có lỗi mởi sảy ra. Đâu có phải vì lỗi cũ?

Tất nhiên bạn có 2 lần kết quả vì bạn dùng Debug.Print 2 lần.
Dạ vâng ạ ! Em đã đọc bài của anh rồi ạ . Và dựa vào câu trả lời của anh thì em cũng đã giải quyết được câu hỏi của mình rồi ! . Em cảm ơn anh nhiều lắm ^^ . Cảm ơn anh đã dành thời gian khắc phục lỗi giúp em
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom