Menu
Coddy logo textTech

Sovrascrittura di noSuchMethod

Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 74 di 110.

Quando chiami un metodo che non esiste su un oggetto, Dart normalmente genera un NoSuchMethodError. Tuttavia, puoi eseguire l'override del metodo speciale noSuchMethod() per intercettare queste chiamate e gestirle in modo appropriato.

Per usare noSuchMethod(), la tua classe deve anche implementare un'interfaccia oppure usare la tipizzazione dynamic.

Il metodo riceve un oggetto Invocation che contiene i dettagli della chiamata tentata:

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

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

L'oggetto Invocation fornisce informazioni utili sulla chiamata: memberName ti dà il nome del metodo come Symbol, positionalArguments contiene gli argomenti passati e isMethod indica se si trattava di una chiamata a un metodo anziché a un getter o a un 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
}

Questa tecnica è utile per creare oggetti proxy, classi mock per i test o API flessibili che rispondono a chiamate arbitrarie ai metodi. Tuttavia, usala con parsimonia, poiché aggira il controllo dei tipi in fase di compilazione.

challenge icon

Sfida

Facile

Costruiamo un logger dei metodi che intercetta e registra qualsiasi chiamata a un metodo effettuata su un oggetto! Creerai una classe che usa noSuchMethod() per acquisire informazioni sulle chiamate a metodi non definiti e rispondere in modo intelligente in base al nome del metodo.

Organizzerai il codice in due file:

  • method_logger.dart: crea una classe MethodLogger che intercetta le chiamate ai metodi non definiti. Il logger deve sovrascrivere noSuchMethod() per:
    • Estrarre il nome del metodo dalla chiamata (sarà un Symbol come Symbol("methodName"): dovrai convertirlo in una stringa ed estrarre solo il nome)
    • Stampare il nome del metodo e gli eventuali argomenti posizionali in questo formato: Called: [methodName] with args: [arguments]
    • Restituire una risposta speciale in base al nome del metodo:
      • Se il nome del metodo contiene get, restituisci la stringa 'data retrieved'
      • Se il nome del metodo contiene save, restituisci la stringa 'data saved'
      • Altrimenti, restituisci la stringa 'unknown action'
  • main.dart: importa il logger e mostra come gestisce varie chiamate a metodi non definiti. Ricorda di usare il tipo dynamic affinché Dart consenta di chiamare metodi che non esistono:
    • Crea un'istanza di MethodLogger usando una variabile di tipo dynamic
    • Chiamaci getUserData('Alice', 42) e stampa il risultato restituito
    • Chiamaci saveRecord('important') e stampa il risultato restituito
    • Chiamaci processItem() (senza argomenti) e stampa il risultato restituito

Per estrarre il nome del metodo da un Symbol, puoi convertirlo in una stringa e poi ricavare il nome racchiuso tra virgolette. Per esempio, Symbol("myMethod").toString() restituisce 'Symbol("myMethod")'.

Output previsto:

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

Provalo tu

import 'method_logger.dart';

void main() {
  // TODO: Crea un'istanza di MethodLogger usando la tipizzazione dinamica
  // L'uso di dynamic permette di chiamare metodi che non esistono in fase di compilazione
  dynamic logger;
  
  // TODO: Chiama getUserData('Alice', 42) e stampa il risultato
  
  // TODO: Chiama saveRecord('important') e stampa il risultato
  
  // TODO: Chiama processItem() senza argomenti e stampa il risultato
  
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Dart online