דריסת noSuchMethod
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Dart של Coddy. שיעור 74 מתוך 110.
כשקוראים למתודה שלא קיימת באובייקט, Dart בדרך כלל זורקת NoSuchMethodError. עם זאת, אפשר לדרוס את המתודה המיוחדת noSuchMethod() כדי ליירט קריאות כאלה ולטפל בהן בצורה תקינה.
כדי להשתמש ב־noSuchMethod(), המחלקה שלך חייבת גם לממש ממשק או להשתמש בטיפוס dynamic.
המתודה מקבלת אובייקט Invocation שמכיל פרטים על הקריאה שנוסתה:
class Flexible {
@override
dynamic noSuchMethod(Invocation invocation) {
var methodName = invocation.memberName.toString();
print('Called: $methodName');
return null;
}
}
void main() {
dynamic obj = Flexible();
obj.anyMethod(); // נקרא: Symbol("anyMethod")
obj.anotherOne(42); // נקרא: Symbol("anotherOne")
}האובייקט Invocation מספק מידע שימושי על הקריאה — memberName נותן לך את שם המתודה כסמל, positionalArguments מכיל את הארגומנטים שהועברו, ו־isMethod מציין אם זו הייתה קריאה למתודה ולא ל־getter או ל־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); // טופל
}הטכניקה הזו שימושית ליצירת אובייקטי פרוקסי, מחלקות מדומות לבדיקה או בניית ממשקי API גמישים שמגיבים לקריאות שרירותיות למתודות. עם זאת, השתמשו בה במתינות, מכיוון שהיא עוקפת בדיקת טיפוסים בזמן הידור.
אתגר
קלבואו נבנה מתעד מתודות שמיירט ומתעד כל קריאה למתודה שמתבצעת באובייקט! תיצרו מחלקה שמשתמשת ב־noSuchMethod() כדי ללכוד מידע על קריאות למתודות לא מוגדרות ולהגיב בצורה חכמה בהתאם לשם המתודה.
תארגנו את הקוד בשני קבצים:
method_logger.dart: צרו מחלקה בשםMethodLoggerשמיירטת קריאות למתודות לא מוגדרות. המתעד שלכם צריך לדרוס אתnoSuchMethod()כדי:- לחלץ את שם המתודה מתוך הקריאה (הוא יהיה Symbol כמו
Symbol("methodName")— תצטרכו להמיר אותו למחרוזת ולחלץ רק את השם) - להדפיס את שם המתודה ואת הארגומנטים המיקומיים, אם ישנם, בפורמט הזה:
Called: [methodName] with args: [arguments] - להחזיר תגובה מיוחדת בהתאם לשם המתודה:
- אם שם המתודה מכיל
get, להחזיר את המחרוזת'data retrieved' - אם שם המתודה מכיל
save, להחזיר את המחרוזת'data saved' - אחרת, להחזיר את המחרוזת
'unknown action'
- אם שם המתודה מכיל
- לחלץ את שם המתודה מתוך הקריאה (הוא יהיה Symbol כמו
main.dart: ייבאו את המתעד והדגימו כיצד הוא מטפל בקריאות שונות למתודות לא מוגדרות. זכרו להשתמש בטיפוסdynamicכדי ש־Dart תאפשר לקרוא למתודות שלא קיימות:- צרו מופע של
MethodLoggerבאמצעות משתנה מטיפוס dynamic - קראו לו עם
getUserData('Alice', 42)והדפיסו את התוצאה שהוחזרה - קראו לו עם
saveRecord('important')והדפיסו את התוצאה שהוחזרה - קראו לו עם
processItem()(ללא ארגומנטים) והדפיסו את התוצאה שהוחזרה
- צרו מופע של
כדי לחלץ את שם המתודה מתוך Symbol, אפשר להמיר אותו למחרוזת ואז לחלץ את השם שמופיע בין המרכאות. לדוגמה, Symbol("myMethod").toString() נותן לכם את 'Symbol("myMethod")'.
הפלט הצפוי:
Called: getUserData with args: [Alice, 42]
data retrieved
Called: saveRecord with args: [important]
data saved
Called: processItem with args: []
unknown actionנסו בעצמכם
import 'method_logger.dart';
void main() {
// TODO: צרו מופע של MethodLogger באמצעות טיפוס דינמי
// השימוש ב-dynamic מאפשר לקרוא למתודות שאינן קיימות בזמן הקומפילציה
dynamic logger;
// TODO: קראו ל-getUserData('Alice', 42) והדפיסו את התוצאה
// TODO: קראו ל-saveRecord('important') והדפיסו את התוצאה
// TODO: קראו ל-processItem() ללא ארגומנטים והדפיסו את התוצאה
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםספריות וייבואמבוא לתכנות מונחה עצמיםמחלקות לעומת אובייקטיםמילת המפתח thisמתודותמשתני מופעיסודות הבנאיחזרה: מחשבון פשוט4בטיחות מפני ערכי null
מבוא לבטיחות מפני ערכי nullניתן להקצאה ל-null לעומת לא ניתן להקצאה ל-nullהאופרטורים ? ו-!מילת המפתח Late ובטיחות מפני ערכי nullאופרטורים מודעי nullבטיחות מפני ערכי null במחלקותסיכום – מערכת פרופילי משתמשים7מחלקות מופשטות וממשקים
מחלקות מופשטותמתודות מופשטותממשקים ב-Dartממשקים משתמעיםמימוש לעומת הורשהממשקים מרוביםחזרה – מחשבון צורות10אוספים וגנריות
סקירה כללית של List, Set ו-Mapאוספים בטוחים מבחינת טיפוסיםמחלקות גנריותמתודות גנריותאילוצים גנרייםIterable ו-Iteratorסיכום – אחסון גנרי13מושגי OOP מתקדמים
הרכבה לעומת הורשהמתודות הרחבהמחלקות קריאותמחלקות אטומות (Dart 3)רשומות (Dart 3)תבניות והתאמה (3.0)טיפוסים מונים עם מתודות16פרויקט: ניהול ספרייה
סקירת הפרויקטמחלקות ספר ומשתמש2בנאים ב-Dart
בנאי ברירת מחדלבנאים בעלי שםרשימות אתחולבנאים קבועיםבנאי Factoryבנאים מפניםסיכום - בונה צורות5כימוס
חברים ציבוריים לעומת פרטייםמוסכמת הקידומת _פרטיות ברמת הספרייההעמקה ב-getters וב-settersהסתרת מידעסיכום – רשומות תלמידים8מיקסינים
מבוא למיקסיניםיצירת מיקסיניםשימוש במספר מיקסיניםמילת המפתח on במיקסיניםמיקסינים לעומת ירושהמיקסינים לעומת ממשקסיכום – מערכת בעלי החיים11מתודות מיוחדות
דריסת toString()דריסת hashCode ו־==הממשק Comparableמתודת call()דריסת noSuchMethodסיכום – אוסף מותאם אישית3מאפייני מחלקה
איברי מופע לעומת איברים סטטייםשדות final ו-constמשתני lateמתודות ושדות סטטייםGetters ו-Settersסיכום – מנהל חשבונות בנק6ירושה
ירושה בסיסיתמילת המפתח superדריסת מתודותהאנוטציה @overrideמילת המפתח final למחלקהבנאים וירושהסיכום – היררכיית עובדים9פולימורפיזם
יסודות הפולימורפיזםפולימורפיזם באמצעות ממשקיםבדיקת טיפוסים בזמן ריצההאופרטורים is ו-asמילת המפתח קווריאנטיסיכום — מעבד תשלומים12תכנות מונחה עצמים אסינכרוני
Future-ים ו-async/awaitיסודות ה-Streamsבקרי Streamsבנאים אסינכרונייםאסינכרוניות במתודות של מחלקהסיכום - אחזור נתוניםתרגלו בעצמכם: קומפיילר Dart אונליין