Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

إعادة تعريف noSuchMethod

جزء من قسم Object Oriented Programming في رحلة Dart على Coddy — الدرس 74 من 110.

عندما تستدعي تابعاً (method) غير موجود في كائن ما، فإن Dart عادةً ما يرمي NoSuchMethodError. ومع ذلك، يمكنك تجاوز التابع الخاص noSuchMethod() لاعتراض هذه الاستدعاءات ومعالجتها بسلاسة.

لاستخدام noSuchMethod()، يجب أن يقوم الصنف (class) الخاص بك أيضًا بتنفيذ واجهة (interface) أو استخدام النوع 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 اسم الطريقة كـ Symbol، ويحتوي 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);  // تمت المعالجة
}

هذه التقنية مفيدة لإنشاء كائنات وكيلة (proxy objects)، أو فئات وهمية (mock classes) للاختبار، أو بناء واجهات برمجة تطبيقات (APIs) مرنة تستجيب لاستدعاءات دوال عشوائية. ومع ذلك، استخدمها باعتدال لأنها تتجاوز التحقق من النوع في وقت التجميع (compile-time type checking).

challenge icon

التحدي

سهل

لنقم ببناء مسجل طرق (method logger) يقوم باعتراض وتسجيل أي استدعاءات للطرق يتم إجراؤها على كائن! ستقوم بإنشاء فئة تستخدم 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 باستخدام متغير ديناميكي
    • استدعِ 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 يسمح باستدعاء الدوال التي لا توجد في compile time
  dynamic logger;
  
  // TODO: قم باستدعاء getUserData('Alice', 42) واطبع النتيجة
  
  // TODO: قم باستدعاء saveRecord('important') واطبع النتيجة
  
  // TODO: قم باستدعاء processItem() بدون وسائط واطبع النتيجة
  
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming