إعادة تعريف 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).
التحدي
سهللنقم ببناء مسجل طرق (method logger) يقوم باعتراض وتسجيل أي استدعاءات للطرق يتم إجراؤها على كائن! ستقوم بإنشاء فئة تستخدم 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باستخدام متغير ديناميكي - استدعِ
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() بدون وسائط واطبع النتيجة
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات الـ OOP
الملفات الخارجيةالمكتبات والـ Importsمقدمة في الـ OOPالـ Classes مقابل الـ Objectsالكلمة المفتاحية thisالـ Methodsمتغيرات الـ Instanceأساسيات الـ Constructorمراجعة - آلة حاسبة بسيطة4أمان الـ Null
مقدمة في أمان الـ NullNullable مقابل Non-Nullableعاملا الـ ? و !الكلمة المفتاحية Late وأمان الـ Nullالعوامل المدركة للـ Nullأمان الـ Null في الـ Classesمراجعة - نظام ملف تعريف المستخدم7الفئات المجردة والواجهات
الفئات المجردةالدوال المجردةالواجهات في Dartالواجهات الضمنيةالتنفيذ مقابل التوسيعالواجهات المتعددةمراجعة - حاسبة الأشكال10المجموعات والأنماط العامة
نظرة عامة على List و Set و Mapالمجموعات آمنة النوعالفئات العامةالدوال العامةقيود الأنماط العامةIterable و Iteratorملخص - التخزين العام13مفاهيم OOP المتقدمة
التركيب مقابل الوراثة (Composition vs Inheritance)دوال التوسعة (Extension Methods)الأصناف القابلة للاستدعاء (Callable Classes)الأصناف المختومة (Sealed Classes - Dart 3)السجلات (Records - Dart 3)الأنماط والمطابقة (Patterns & Matching - 3.0)التعدادات مع الدوال (Enums with Methods)2المنشئات في Dart
المنشئ الافتراضيالمنشئات المسماةقوائم التهيئةالمنشئات الثابتةالمنشئات المصنعيةالمنشئات الموجهةملخص - بناء الأشكال5التغليف (Encapsulation)
الأعضاء العامة مقابل الخاصةاتفاقية البادئة _الخصوصية على مستوى المكتبةتعمق في Getters و Settersإخفاء المعلوماتمراجعة - سجلات الطلاب8Mixins
مقدمة إلى Mixinsإنشاء Mixinsاستخدام Mixins متعددةالكلمة المفتاحية on في MixinsMixin مقابل الوراثة (Inheritance)Mixin مقابل الواجهة (Interface)مراجعة - نظام الحيوانات (Animal System)11الدوال الخاصة
إعادة تعريف toString()إعادة تعريف hashCode و ==واجهة Comparableدالة call()إعادة تعريف noSuchMethodمراجعة - Custom Collection3خصائص الـ Class
أعضاء الـ Instance مقابل الـ Staticحقول Final و Constمتغيرات Lateالـ Static Methods والحقولدوال الـ Getters والـ Settersمراجعة - مدير الحساب البنكي6الوراثة
أساسيات الوراثةالكلمة المفتاحية superإعادة تعريف الدوال (Method Overriding)الوسم @overrideالكلمة المفتاحية final Classالدوال البانية والوراثةمراجعة - هيكلية الموظفين9تعدد الأشكال
أساسيات تعدد الأشكالتعدد الأشكال عبر الـ Interfacesالتحقق من النوع أثناء التشغيلالمعاملات is و asالكلمة المفتاحية Covariantملخص - معالج الدفع12البرمجة الكائنية غير المتزامنة (Async OOP)
Futures و async/awaitأساسيات الـ Streamsمتحكمات الـ Streamsالـ Constructors غير المتزامنةالعمليات غير المتزامنة في دوال الكلاسمراجعة - جالب البيانات (Data Fetcher)15أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المستودع