Menu
CoddyTech

Ghi đè noSuchMethod

Thuộc phần Lập trình hướng đối tượng trong hành trình Dart của Coddy. Bài học 74 trên 110.

Khi bạn gọi một phương thức không tồn tại trên một đối tượng, Dart thường ném ra lỗi NoSuchMethodError. Tuy nhiên, bạn có thể ghi đè phương thức đặc biệt noSuchMethod() để chặn các lần gọi này và xử lý chúng một cách phù hợp.

Để dùng noSuchMethod(), lớp của bạn cũng phải triển khai một interface hoặc dùng kiểu dynamic.

Phương thức nhận một đối tượng Invocation chứa thông tin về lời gọi được thử thực hiện:

class Flexible {
  @override
  dynamic noSuchMethod(Invocation invocation) {
    var methodName = invocation.memberName.toString();
    print('Called: $methodName');
    return null;
  }
}

void main() {
  dynamic obj = Flexible();
  obj.anyMethod();      // Đã gọi: Symbol("anyMethod")
  obj.anotherOne(42);   // Đã gọi: Symbol("anotherOne")
}

Đối tượng Invocation cung cấp thông tin hữu ích về lời gọi: memberName cho bạn biết tên phương thức dưới dạng Symbol, positionalArguments chứa các đối số được truyền vào, còn isMethod cho biết đó là lời gọi phương thức hay getter hoặc setter.

class Logger {
  @override
  dynamic noSuchMethod(Invocation invocation) {
    print('Method: ${invocation.memberName}');
    print('Args: ${invocation.positionalArguments}');
    return 'handled';
  }
}

void main() {
  dynamic log = Logger();
  var result = log.save('data', 123);
  print(result);  // handled
}

Kỹ thuật này hữu ích khi tạo đối tượng proxy, lớp mô phỏng để kiểm thử hoặc xây dựng API linh hoạt có thể phản hồi các lệnh gọi phương thức tùy ý. Tuy nhiên, chỉ nên dùng kỹ thuật này khi cần, vì nó bỏ qua bước kiểm tra kiểu dữ liệu tại thời điểm biên dịch.

challenge icon

Thử thách

Dễ

Hãy tạo một trình ghi nhật ký phương thức để chặn và ghi lại mọi lời gọi phương thức trên một đối tượng! Bạn sẽ tạo một lớp dùng noSuchMethod() để thu thập thông tin về các lời gọi phương thức chưa được định nghĩa và phản hồi phù hợp dựa trên tên phương thức.

Bạn sẽ sắp xếp code vào hai tệp:

  • method_logger.dart: Tạo một lớp MethodLogger để chặn các lời gọi đến phương thức chưa được định nghĩa. Trình ghi nhật ký của bạn cần ghi đè noSuchMethod() để:
    • Lấy tên phương thức từ lời gọi (tên này sẽ là một Symbol như Symbol("methodName"), bạn cần chuyển nó thành chuỗi rồi lấy riêng tên phương thức)
    • In tên phương thức và mọi đối số vị trí theo định dạng này: Called: [methodName] with args: [arguments]
    • Trả về phản hồi đặc biệt dựa trên tên phương thức:
      • Nếu tên phương thức có chứa get, hãy trả về chuỗi 'data retrieved'
      • Nếu tên phương thức có chứa save, hãy trả về chuỗi 'data saved'
      • Nếu không, hãy trả về chuỗi 'unknown action'
  • main.dart: Nhập trình ghi nhật ký và minh họa cách nó xử lý nhiều lời gọi phương thức chưa được định nghĩa. Nhớ dùng kiểu dynamic để Dart cho phép gọi những phương thức không tồn tại:
    • Tạo một đối tượng MethodLogger bằng một biến kiểu dynamic
    • Gọi getUserData('Alice', 42) trên đối tượng đó rồi in kết quả trả về
    • Gọi saveRecord('important') trên đối tượng đó rồi in kết quả trả về
    • Gọi processItem() trên đối tượng đó (không có đối số) rồi in kết quả trả về

Để lấy tên phương thức từ một Symbol, bạn có thể chuyển nó thành chuỗi rồi phân tích để lấy tên nằm giữa các dấu ngoặc kép. Ví dụ, Symbol("myMethod").toString() cho kết quả 'Symbol("myMethod")'.

Đầu ra mong đợi:

Called: getUserData with args: [Alice, 42]
data retrieved
Called: saveRecord with args: [important]
data saved
Called: processItem with args: []
unknown action

Tự làm thử

import 'method_logger.dart';

void main() {
  // TODO: Tạo một instance MethodLogger với kiểu dữ liệu dynamic
  // Dùng dynamic để gọi các phương thức (method) chưa tồn tại tại thời điểm biên dịch
  dynamic logger;
  
  // TODO: Gọi getUserData('Alice', 42) và in ra kết quả
  
  // TODO: Gọi saveRecord('important') và in ra kết quả
  
  // TODO: Gọi processItem() không có đối số (argument) và in ra kết quả
  
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Dart online