Menu
Coddy logo textTech

דריסת 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 גמישים שמגיבים לקריאות שרירותיות למתודות. עם זאת, השתמשו בה במתינות, מכיוון שהיא עוקפת בדיקת טיפוסים בזמן הידור.

challenge icon

אתגר

קל

בואו נבנה מתעד מתודות שמיירט ומתעד כל קריאה למתודה שמתבצעת באובייקט! תיצרו מחלקה שמשתמשת ב־noSuchMethod() כדי ללכוד מידע על קריאות למתודות לא מוגדרות ולהגיב בצורה חכמה בהתאם לשם המתודה.

תארגנו את הקוד בשני קבצים:

  • method_logger.dart: צרו מחלקה בשם MethodLogger שמיירטת קריאות למתודות לא מוגדרות. המתעד שלכם צריך לדרוס את noSuchMethod() כדי:
    • לחלץ את שם המתודה מתוך הקריאה (הוא יהיה Symbol כמו Symbol("methodName") — תצטרכו להמיר אותו למחרוזת ולחלץ רק את השם)
    • להדפיס את שם המתודה ואת הארגומנטים המיקומיים, אם ישנם, בפורמט הזה: Called: [methodName] with args: [arguments]
    • להחזיר תגובה מיוחדת בהתאם לשם המתודה:
      • אם שם המתודה מכיל get, להחזיר את המחרוזת 'data retrieved'
      • אם שם המתודה מכיל save, להחזיר את המחרוזת 'data saved'
      • אחרת, להחזיר את המחרוזת 'unknown action'
  • 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() ללא ארגומנטים והדפיסו את התוצאה
  
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Dart אונליין