Menu
Coddy logo textTech

Sobrescritura de noSuchMethod

Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy. Lección 74 de 110.

Cuando llamas a un método que no existe en un objeto, Dart normalmente lanza un NoSuchMethodError. Sin embargo, puedes sobrescribir el método especial noSuchMethod() para interceptar estas llamadas y manejarlas de forma adecuada.

Para usar noSuchMethod(), tu clase también debe implementar una interfaz o usar tipado dynamic.

El método recibe un objeto Invocation que contiene detalles sobre la llamada intentada:

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

void main() {
  dynamic obj = Flexible();
  obj.anyMethod();      // Llamado: Symbol("anyMethod")
  obj.anotherOne(42);   // Llamado: Symbol("anotherOne")
}

El objeto Invocation proporciona información útil sobre la llamada: memberName te da el nombre del método como un símbolo, positionalArguments contiene los argumentos proporcionados y isMethod te indica si se trató de una llamada a un método en lugar de un getter o 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);  // manejado
}

Esta técnica es útil para crear objetos proxy, clases mock para pruebas o construir APIs flexibles que respondan a llamadas de métodos arbitrarios. Sin embargo, úsela con moderación ya que omite la comprobación de tipos en tiempo de compilación.

challenge icon

Desafío

Fácil

¡Construyamos un registrador de métodos que intercepte y registre cualquier llamada a métodos realizada sobre un objeto! Crearás una clase que use noSuchMethod() para capturar información sobre las llamadas a métodos no definidos y responder de forma inteligente según el nombre del método.

Organizarás tu código en dos archivos:

  • method_logger.dart: Crea una clase MethodLogger que intercepte las llamadas a métodos no definidos. Tu registrador debe sobrescribir noSuchMethod() para:
    • Extraer el nombre del método de la invocación (será un Symbol como Symbol("methodName"); tendrás que convertirlo en una cadena y extraer únicamente el nombre)
    • Imprimir el nombre del método y cualquier argumento posicional con este formato: Called: [methodName] with args: [arguments]
    • Devolver una respuesta especial según el nombre del método:
      • Si el nombre del método contiene get, devuelve la cadena 'data retrieved'
      • Si el nombre del método contiene save, devuelve la cadena 'data saved'
      • De lo contrario, devuelve la cadena 'unknown action'
  • main.dart: Importa tu registrador y demuestra cómo gestiona varias llamadas a métodos no definidos. Recuerda usar el tipado dynamic para que Dart permita llamar a métodos que no existen:
    • Crea una instancia de MethodLogger usando una variable dinámica
    • Llama a getUserData('Alice', 42) y muestra el resultado devuelto
    • Llama a saveRecord('important') y muestra el resultado devuelto
    • Llama a processItem() (sin argumentos) y muestra el resultado devuelto

Para extraer el nombre del método de un Symbol, puedes convertirlo en una cadena y después extraer el nombre que está entre las comillas. Por ejemplo, Symbol("myMethod").toString() produce 'Symbol("myMethod")'.

Salida esperada:

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

Pruébalo tú mismo

import 'method_logger.dart';

void main() {
  // TODO: Crea una instancia de MethodLogger usando tipado dynamic
  // El uso de dynamic permite llamar a métodos que no existen en tiempo de compilación
  dynamic logger;
  
  // TODO: Llama a getUserData('Alice', 42) e imprime el resultado
  
  // TODO: Llama a saveRecord('important') e imprime el resultado
  
  // TODO: Llama a processItem() sin argumentos e imprime el resultado
  
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Dart online