noSuchMethod-Überschreibung
Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy. Lektion 74 von 110.
Wenn Sie eine Methode aufrufen, die für ein Objekt nicht existiert, wirft Dart normalerweise einen NoSuchMethodError. Sie können jedoch die spezielle noSuchMethod()-Methode überschreiben, um diese Aufrufe abzufangen und sie angemessen zu behandeln.
Um noSuchMethod() zu verwenden, muss Ihre Klasse auch eine Schnittstelle implementieren oder dynamic Typisierung verwenden.
Die Methode erhält ein Invocation-Objekt, das Details über den versuchten Aufruf enthält:
class Flexible {
@override
dynamic noSuchMethod(Invocation invocation) {
var methodName = invocation.memberName.toString();
print('Called: $methodName');
return null;
}
}
void main() {
dynamic obj = Flexible();
obj.anyMethod(); // Aufgerufen: Symbol("anyMethod")
obj.anotherOne(42); // Aufgerufen: Symbol("anotherOne")
}Das Invocation-Objekt bietet nützliche Informationen über den Aufruf – memberName liefert Ihnen den Methodennamen als Symbol, positionalArguments enthält die übergebenen Argumente und isMethod gibt an, ob es sich um einen Methodenaufruf im Gegensatz zu einem Getter oder Setter handelte.
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
}Diese Technik ist nützlich für das Erstellen von Proxy-Objekten, Mock-Klassen für Tests oder den Aufbau flexibler APIs, die auf beliebige Methodenaufrufe reagieren. Verwenden Sie sie jedoch sparsam, da sie die Typprüfung zur Kompilierzeit umgeht.
Aufgabe
EinfachLass uns einen Methoden-Logger erstellen, der alle Methodenaufrufe abfängt und aufzeichnet, die an einem Objekt vorgenommen werden! Du erstellst eine Klasse, die noSuchMethod() verwendet, um Informationen über Aufrufe nicht definierter Methoden zu erfassen und abhängig vom Methodennamen intelligent zu reagieren.
Du organisierst deinen Code in zwei Dateien:
method_logger.dart: Erstelle eineMethodLogger-Klasse, die Aufrufe nicht definierter Methoden abfängt. Dein Logger solltenoSuchMethod()überschreiben, um:- Den Methodennamen aus dem Aufruf zu extrahieren (er wird ein Symbol wie
Symbol("methodName")sein – du musst es in einen String umwandeln und nur den Namen extrahieren) - Den Methodennamen und alle Positionsargumente in diesem Format auszugeben:
Called: [methodName] with args: [arguments] - Abhängig vom Methodennamen eine spezielle Antwort zurückzugeben:
- Wenn der Methodenname
getenthält, gib den String'data retrieved'zurück - Wenn der Methodenname
saveenthält, gib den String'data saved'zurück - Andernfalls gib den String
'unknown action'zurück
- Wenn der Methodenname
- Den Methodennamen aus dem Aufruf zu extrahieren (er wird ein Symbol wie
main.dart: Importiere deinen Logger und demonstriere, wie er verschiedene Aufrufe nicht definierter Methoden verarbeitet. Denke daran, die Typisierungdynamiczu verwenden, damit Dart den Aufruf nicht vorhandener Methoden erlaubt:- Erstelle eine
MethodLogger-Instanz mithilfe einer dynamischen Variable - Rufe
getUserData('Alice', 42)auf ihr auf und gib das zurückgegebene Ergebnis aus - Rufe
saveRecord('important')auf ihr auf und gib das zurückgegebene Ergebnis aus - Rufe
processItem()auf ihr auf (ohne Argumente) und gib das zurückgegebene Ergebnis aus
- Erstelle eine
Um den Methodennamen aus einem Symbol zu extrahieren, kannst du es in einen String umwandeln und anschließend den Namen zwischen den Anführungszeichen herausparsen. Zum Beispiel liefert Symbol("myMethod").toString() den Wert 'Symbol("myMethod")'.
Erwartete Ausgabe:
Called: getUserData with args: [Alice, 42]
data retrieved
Called: saveRecord with args: [important]
data saved
Called: processItem with args: []
unknown actionProbier es selbst
import 'method_logger.dart';
void main() {
// TODO: Erstelle eine MethodLogger-Instanz unter Verwendung von dynamic Typisierung
// Die Verwendung von dynamic ermöglicht den Aufruf von Methoden, die zur Kompilierzeit nicht existieren
dynamic logger;
// TODO: Rufe getUserData('Alice', 42) auf und gib das Ergebnis aus
// TODO: Rufe saveRecord('important') auf und gib das Ergebnis aus
// TODO: Rufe processItem() ohne Argumente auf und gib das Ergebnis aus
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienBibliotheken & ImportsEinführung in die OOPKlassen vs. ObjekteDas Schlüsselwort thisMethodenInstanzvariablenGrundlagen von KonstruktorenRückblick – Einfacher Taschenrechner4Null-Sicherheit
Einführung in die Null-SicherheitNullable vs. Non-NullableDie Operatoren ? und !Late-Schlüsselwort und Null-SicherheitNull-bewusste OperatorenNull-Sicherheit in KlassenRückblick – Benutzers профilsystem7Abstrakte Klassen & Interfaces
Abstrakte KlassenAbstrakte MethodenInterfaces in DartImplizite InterfacesImplementieren vs. ErweiternMehrere InterfacesZusammenfassung – Formrechner10Collections & Generics
Übersicht über List, Set und MapTypsichere CollectionsGenerische KlassenGenerische MethodenGenerische EinschränkungenIterable & IteratorRückblick – Generischer Speicher13Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungErweiterungsmethodenAufrufbare KlassenVersiegelte Klassen (Dart 3)Records (Dart 3)Muster & Matching (3.0)Enums mit Methoden16Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen2Konstruktoren in Dart
StandardkonstruktorBenannte KonstruktorenInitialisierungslistenKonstantenkonstruktorenFactory-KonstruktorenWeiterleitende KonstruktorenRückblick – Shape Builder5Kapselung
Öffentliche vs. private MemberDie _-Präfix-KonventionBibliotheksweite SichtbarkeitTiefergehende Getter & SetterInformationsverbergungRückblick – Studierendendaten8Mixins
Einführung in MixinsMixins erstellenMehrere Mixins verwendenDas Schlüsselwort „on“ in MixinsMixin vs. VererbungMixin vs. SchnittstelleRückblick – Tiersystem11Spezielle Methoden
toString()-ÜberschreibunghashCode- & ==-ÜberschreibungComparable-Schnittstellecall()-MethodenoSuchMethod-ÜberschreibungWiederholung – Benutzerdefinierte Collection14Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFabrikmusterBeobachtermusterStrategiemuster17Abschließende Herausforderungen
E-Learning-PlattformBankingsystemSpielcharaktersystemFahrzeugvermietung3Klassen-Eigenschaften
Instanz- vs. statische MemberFinal- und Const-FelderLate-VariablenStatische Methoden und FelderGetter und SetterRückblick – Bankkontoverwaltung6Vererbung
Grundlegende VererbungDas Schlüsselwort superMethodenüberschreibungDie Annotation @overrideDas Schlüsselwort final für KlassenKonstruktoren und VererbungZusammenfassung – Mitarbeiterhierarchie9Polymorphismus
Grundlagen des PolymorphismusPolymorphismus über InterfacesLaufzeit-TypüberprüfungDie Operatoren is & asCovariant-SchlüsselwortZusammenfassung – ZahlungsprozessorÜbe selbstständig: Online-Dart-Compiler