البرمجة التأملية
في علوم الحاسوب ، تُعرف البرمجة التأملية أو التأمل بأنها قدرة العملية على فحص ودراسة وتعديل بنيتها وسلوكها. [ 1 ]
الخلفية التاريخية
تمت برمجة الحواسيب الأولى بلغات التجميع الأصلية ، والتي كانت بطبيعتها انعكاسية، حيث كان من الممكن برمجة هذه البنى الأصلية بتعريف التعليمات كبيانات واستخدام شيفرة ذاتية التعديل . ومع انتقال معظم البرمجة إلى لغات مُجمّعة عالية المستوى مثل ALGOL و COBOL و Fortran و Pascal و C ، اختفت هذه القدرة الانعكاسية إلى حد كبير حتى ظهور لغات برمجة جديدة تتضمن الانعكاس مُدمجًا في أنظمة أنواعها.
قدمت أطروحة الدكتوراه التي قدمها برايان كانتويل سميث عام 1982 مفهوم الانعكاس الحسابي في لغات البرمجة الإجرائية ومفهوم المفسر الدائري الفائق كمكون من مكونات لغة 3- Lisp . [ 2 ] [ 3 ]
الاستخدامات
تساعد تقنية الانعكاس المبرمجين على إنشاء مكتبات برمجية عامة لعرض البيانات، ومعالجة تنسيقات البيانات المختلفة، وإجراء عمليات التسلسل وفك التسلسل للبيانات لأغراض الاتصال، أو تجميع البيانات وفك تجميعها للحاويات أو دفعات الاتصال. قد توفر الأنظمة الانعكاسية نوع المرآة ، الذي يُستخدم كانعكاس منفصل لكائن أو مُعرِّف.
يتطلب الاستخدام الفعال للانعكاس دائمًا تقريبًا وجود خطة: إطار تصميم، وصف ترميز، مكتبة كائنات، خريطة لقاعدة بيانات أو علاقات الكيانات.
تُحسّن خاصية الانعكاس من ملاءمة لغة البرمجة للبرمجة الموجهة للشبكات. فعلى سبيل المثال، تُساعد لغات مثل جافا على العمل بكفاءة في الشبكات من خلال توفير مكتبات للتسلسل والتجميع وتنسيقات البيانات المختلفة. أما اللغات التي لا تدعم الانعكاس، مثل لغة سي، فتحتاج إلى استخدام مُترجمات مساعدة لمهام مثل تدوين بناء الجملة المجرد ( ASN.1 ) لإنتاج التعليمات البرمجية اللازمة للتسلسل والتجميع.
يمكن استخدام تقنية الانعكاس لمراقبة وتعديل تنفيذ البرنامج أثناء التشغيل . يستطيع مكون البرنامج الموجه نحو الانعكاس مراقبة تنفيذ مجموعة من التعليمات البرمجية، وتعديل نفسه وفقًا لهدف محدد لتلك المجموعة. ويتم ذلك عادةً عن طريق تعيين التعليمات البرمجية للبرنامج ديناميكيًا أثناء التشغيل.
في لغات البرمجة كائنية التوجه مثل جافا ، يسمح الانعكاس بفحص الفئات والواجهات والحقول والأساليب أثناء وقت التشغيل دون معرفة أسماء الواجهات والحقول والأساليب أثناء وقت الترجمة . كما يسمح بإنشاء كائنات جديدة واستدعاء الأساليب.
غالبًا ما يتم استخدام الانعكاس كجزء من اختبار البرمجيات ، مثل إنشاء/تهيئة الكائنات الوهمية في وقت التشغيل .
يُعدّ التفكير أيضاً استراتيجية أساسية للبرمجة الفوقية .
في بعض لغات البرمجة كائنية التوجه، مثل C# و Java ، يُمكن استخدام الانعكاس لتجاوز قواعد الوصول إلى الأعضاء . بالنسبة لخصائص C#، يُمكن تحقيق ذلك بالكتابة مباشرةً إلى حقل الدعم (غير المرئي عادةً) لخاصية غير عامة. كما يُمكن العثور على توابع غير عامة للفئات والأنواع واستدعائها يدويًا. ينطبق هذا على الملفات الداخلية للمشروع، بالإضافة إلى المكتبات الخارجية مثل تجميعات .NET وأرشيفات Java.
تطبيق
توفر اللغة التي تدعم خاصية الانعكاس عددًا من الميزات المتاحة أثناء التشغيل، والتي يصعب تحقيقها في لغة منخفضة المستوى. ومن هذه الميزات القدرة على:
- اكتشف وعدّل بنى الشيفرة المصدرية (مثل كتل الشيفرة، والفئات ، والأساليب، والبروتوكولات، وما إلى ذلك) ككائنات من الدرجة الأولى أثناء التشغيل . يتم توفير بيانات تعريف الكائن القابلة للقراءة كمرآة .
- حوّل سلسلة نصية تطابق الاسم الرمزي لفئة أو دالة إلى مرجع أو استدعاء لتلك الفئة أو الدالة. [ 4 ]
- قم بتقييم سلسلة نصية كما لو كانت عبارة برمجية في وقت التشغيل. [ 5 ] [ 6 ]
- قم بإنشاء مترجم جديد لرمز البايت الخاص باللغة لإعطاء معنى أو غرض جديد لبنية برمجية.
يمكن تطبيق هذه الميزات بطرق مختلفة. في البرمجة متعددة الكائنات ، يُعدّ الانعكاس جزءًا أساسيًا من أساليب البرمجة اليومية. عند استدعاء الدوال (الأساليب)، تُملأ متغيرات مختلفة، مثل verb(اسم الدالة المستدعاة) و this(الكائن الذي استُدعيت عليه الدالة)، لتوفير سياق الاستدعاء. تُدار الحماية عادةً من خلال الوصول إلى مكدس الدوال المستدعِية برمجيًا: بما أن callers()هي قائمة بالأساليب التي استُدعيت بها الدالة الحالية، فإن إجراء اختبارات على callers()[0](الأمر الذي استدعاه المستخدم الأصلي) يسمح للدالة بحماية نفسها من الاستخدام غير المصرح به.
تعتمد اللغات المُترجمة على نظام التشغيل الخاص بها لتوفير معلومات حول شفرة المصدر. فعلى سبيل المثال، يسجل ملف تنفيذي مُترجم بلغة Objective-C أسماء جميع الدوال في كتلة معينة من الملف، مُوفراً جدولاً يربط هذه الأسماء بالدوال الأساسية (أو مُحدِّدات هذه الدوال) المُترجمة في البرنامج. أما في اللغات المُترجمة التي تدعم إنشاء الدوال أثناء التشغيل، مثل Common Lisp ، فيجب أن تتضمن بيئة التشغيل مُترجماً أو مُفسِّراً.
يمكن تطبيق خاصية الانعكاس للغات التي لا تحتوي على خاصية الانعكاس المدمجة باستخدام نظام تحويل البرامج لتحديد تغييرات التعليمات البرمجية المصدرية الآلية.
الاعتبارات الأمنية
قد يسمح الانعكاس للمستخدم بإنشاء مسارات تحكم غير متوقعة داخل التطبيق، مما قد يؤدي إلى تجاوز إجراءات الأمان. ويمكن للمهاجمين استغلال هذه الثغرة. [ 7 ] سمحت ثغرات تاريخية في جافا، ناجمة عن الانعكاس غير الآمن، باختراق آلية الأمان الخاصة ببيئة جافا المعزولة (Sandbox) عن طريق استرجاع التعليمات البرمجية من أجهزة بعيدة يُحتمل عدم موثوقيتها . وخلصت دراسة واسعة النطاق أجريت عام 2013 على 120 ثغرة في جافا إلى أن الانعكاس غير الآمن هو أكثر الثغرات شيوعًا في جافا، وإن لم يكن الأكثر استغلالًا. [ 8 ]
أداء وقت التشغيل
تُضيف أنظمة الانعكاس أثناء التشغيل عبئًا ملحوظًا على أداء وقت التشغيل . على سبيل المثال، في لغة جافا ، نظرًا لأن عمليات الانعكاس تُحل ديناميكيًا أثناء التنفيذ، لا يمكن تطبيق العديد من تحسينات المُصرّف وآلة جافا الافتراضية (JVM) بشكل كامل ، مثل تضمين الدوال ، والربط الثابت ، والتخصيص الفوري المكثف. ونتيجةً لذلك، تكون استدعاءات الانعكاس أبطأ عادةً من نظيراتها المُحلّلة ثابتًا. وقد أظهرت دراسات المعايير الدقيقة ودراسات مستوى التطبيق على جافا أن عمليات الانعكاس قد تُسبب عبئًا كبيرًا على وقت التشغيل، خاصةً لاستدعاء الدوال وإنشاء الكائنات الديناميكية، مع تباطؤ يتراوح بين 20-40% في الحالات المتوسطة إلى أكثر من 300 ضعف في سيناريوهات الإرسال الانعكاسي المكثف. [ 9 ] في التطبيقات التسلسلية، يُمكن أن يزيد الانعكاس بشكل كبير من وقت التنفيذ واستهلاك الذاكرة عند استخدامه في مسارات التعليمات البرمجية الحساسة للأداء. في التطبيقات متعددة الخيوط ، تحافظ التطبيقات الانعكاسية عمومًا على قابلية التوسع ، ولكنها لا تزال تُظهر أوقات تنفيذ مطلقة أعلى بشكل ملحوظ - أبطأ عادةً ما بين 1.5 و 10 مرات - من التعليمات البرمجية غير الانعكاسية المكافئة. [ 9 ]
في لغات مثل C++ و Rust ، يتم تنفيذ عملية الانعكاس أثناء الترجمة . أنظمة الانعكاس أثناء الترجمة أضعف من أنظمة الانعكاس أثناء التشغيل مثل تلك الموجودة في Java و C#، ولكنها لا تتسبب في أي تكلفة إضافية أثناء التشغيل نظرًا لتنفيذها أثناء الترجمة. [ 10 ]
أمثلة
تُنشئ مقتطفات الشفرة التالية نسخةfoo من الفئةFoo وتستدعي أسلوبهاPrintHello . لكل لغة برمجة ، يتم عرض تسلسلات الاستدعاء العادية والقائمة على الانعكاس.
لغة الشفرة الشائعة
المثال أدناه مكتوب بلغة Common Lisp باستخدام نظام كائنات Common Lisp :
( defclass foo () ()) ( defmethod print-hello (( f foo )) ( format T "Hello from ~S~%" f ));; عادي، بدون انعكاس ( let (( foo ( make-instance 'foo ))) ( print-hello foo ))باستخدام الانعكاس، يتم البحث عن الصنف المسمى "foo" والدالة المسماة "print-hello" التي تختص بـ "foo". ( let* (( foo-class ( find-class ( read-from-string "foo" ))) ( print-hello-method ( find-method ( symbol-function ( read-from-string "print-hello" )) nil ( list foo-class )))) ( funcall ( sb-mop:method-generic-function print-hello-method ) ( make-instance foo-class )))ج
لا يمكن إجراء الانعكاس في لغة C ، على الرغم من إمكانية محاكاة أجزاء من الانعكاس.
#include <stdio.h> #include <stdlib.h> #include <string.h>typedef struct { // ... } Foo ;typedef void ( * Method )( void * );// الدالة: Foo::printHello void Foo_printHello ( void * _ ) { printf ( "Hello, world! \n " ); }// جدول الأساليب المُحاكى typedef struct { const char * name ; Method fn ; } MethodEntry ;const MethodEntry FOO_METHODS [] = { { "printHello" , Foo_printHello }, { NULL , NULL } // Sentinel to mark end };// محاكاة البحث الانعكاسي عن الدالة ` findMethodByName` ( const char * name ) { for ( size_t i = 0 ; FOO_METHODS [ i ]. name ; i ++ ) { if ( strcmp ( FOO_METHODS [ i ]. name , name ) == 0 ) { return FOO_METHODS [ i ]. fn ; } } return NULL ; }int main () { // بدون استخدام الانعكاس Foo foo ; Foo_printHello ( & foo );// مع محاكاة الانعكاس Foo * reflected = ( Foo * ) malloc ( sizeof ( Foo )); if ( ! reflected ) { fprintf ( stderr , "فشل تخصيص الذاكرة \n " ); return EXIT_FAILURE ; }const char * name = "printHello" ; Method m = findMethodByName ( name );إذا كان ( m ) { m ( reflected ); } وإلا { fprintf ( stderr , "لم يتم العثور على الطريقة '%s' \n " , name ); free ( reflected ); return EXIT_FAILURE ; }حرر ( منعكس )؛ أرجع نجاح الخروج ؛ }لغة سي++
المثال أدناه مكتوب بلغة C++ (باستخدام خاصية الانعكاس المضافة في C++26 ). [ 11 ]
استيراد std ؛باستخدام std :: string_view ؛ باستخدام std :: views :: filter ؛ باستخدام std :: meta :: access_context ؛ باستخدام std :: meta :: exception ؛ باستخدام std :: meta :: info ؛namespace meta = std :: meta ;consteval bool isNonstaticMethod ( info mem ) noexcept { return meta :: is_class_member ( mem ) && ! meta :: is_static_member ( mem ) && meta :: is_function ( mem ); }consteval info findMethod ( info type , string_view name ) { for ( info member : meta :: members_of ( type , access_context :: current ()) | filter ( isNonstaticMethod )) { if ( meta :: has_identifier ( member ) && meta :: identifier_of ( member ) == name ) { return member ; } } // ملاحظة: هذا استثناء من نوع std::meta::exception، وليس std::exception throw exception ( std :: format ( "فشل استرجاع الدالة {} من النوع {}" , name , meta :: identifier_of ( type )), ^^ findMethod ); }template < info T , const char * Name > constexpr auto createInvokerImpl = []() -> auto { static constexpr info M = findMethod ( T , Name ); contract_assert ( meta :: parameters_of ( M ). size () == 0 && meta :: return_type_of ( M ) == ^^ void ); return []([ : T : ] & instance ) -> void { instance .[ : M : ](); }; }();consteval info createInvoker ( info type , string_view name ) { return meta :: substitute ( ^^ createInvokerImpl , { meta :: reflect_constant ( type ), meta :: reflect_constant_string ( name ) } ); }class Foo { private : // ... public : Foo () = default ;void printHello () const { std :: println ( "Hello, world!" ); } };int main ( int argc , char * argv []) { Foo foo ;// بدون استخدام الانعكاس foo.printHello ( );// باستخدام الانعكاس ، يتم استدعاء الدالة invokePrint تلقائيًا على النحو التالي : ` [ : createInvoker ( ^^ Foo , "printHello" ) : ]; invokePrint ( foo );`return 0 ; }سي شارب
المثال أدناه مكتوب بلغة C# :
namespace Wikipedia.Examples ;باستخدام System ؛ باستخدام System.Reflection ؛class Foo { // ...public void PrintHello () { Console . WriteLine ( "Hello, world!" ); } }public class InvokeFooExample { static void Main ( string [] args ) { // بدون استخدام الانعكاس Foo foo = new (); foo . PrintHello ();// باستخدام الانعكاس Object reflectedFoo = Activator.CreateInstance ( typeof ( Foo ) ) ; MethodInfo method = reflectedFoo.GetType ( ) . GetMethod ( " PrintHello" ); method.Invoke ( foo , null ) ; } }دلفي، أوبجكت باسكال
يفترض هذا المثال المكتوب بلغة دلفي وأوبجكت باسكال أنه تم تعريف فئة TFoo في وحدة تسمى Unit1 :
يستخدم RTTI ، الوحدة 1 ؛إجراء بدون انعكاس ؛ متغير Foo : TFoo ؛ ابدأ Foo : = TFoo.Create ؛ حاول Foo.Hello ؛ أخيرًا Foo.Free ؛ نهاية ؛ نهاية ؛إجراء WithReflection ؛ متغير RttiContext : TRttiContext ؛ متغير RttiType : TRttiInstanceType ؛ متغير Foo : TObject ؛ ابدأ RttiType : = RttiContext.FindType ( ' Unit1.TFoo' ) as TRttiInstanceType ؛ Foo : = RttiType.GetMethod ( 'Create' ) . Invoke ( RttiType.MetaclassType , [ ] ) . AsObject ؛ حاول RttiType.GetMethod ( ' Hello ' ) . Invoke ( Foo , [ ] ) ؛ أخيرًا Foo.Free ؛ نهاية ؛ نهاية ؛إلكترون فولت
المثال أدناه مكتوب بلغة eC:
// بدون استخدام الانعكاس Foo foo {}; foo . hello ();// باستخدام الانعكاس Class fooClass = eSystem_FindClass ( __thisModule , "Foo" ) ; Instance foo = eInstance_New ( fooClass ); Method m = eClass_FindMethod ( fooClass , " hello" , fooClass.module ); (( void ( * )())( void * ) m.function ) ( foo );يذهب
المثال أدناه مكتوب بلغة Go :
استيراد ( "fmt" "reflect" )نوع Foo struct {}func ( f Foo ) Hello () { fmt . Println ( "Hello, world!" ) }func main () { // بدون استخدام الانعكاس var f Foo f . Hello ()// باستخدام الانعكاس ، var fT reflect.Type = reflect.TypeOf ( Foo { } ) var fV reflect.Value = reflect.New ( fT )var m reflect . Value = fV . MethodByName ( "Hello" )إذا كانت m.IsValid ( ) { m.Call ( nil ) } وإلا { fmt.Println ( " لم يتم العثور على الطريقة " ) } }جافا
المثال أدناه مكتوب بلغة جافا :
package org.wikipedia.examples ;استيراد java.lang.reflect.Method ;class Foo { // ...public void printHello () { System . out . println ( "Hello, world!" ); } }public class InvokeFooExample { public static void main ( String [] args ) { // بدون استخدام الانعكاس Foo foo = new Foo (); foo . printHello ();// باستخدام الانعكاس try { Foo reflectedFoo = Foo.class.getDeclaredConstructor ( ) . newInstance ( ) ;Method m = reflectiveFoo.getClass () . getDeclaredMethod ( "printHello" , new Class <?>[ 0 ] ) ; m.invoke ( reflectiveFoo ) ; } catch ( ReflectiveOperationException e ) { System.err.printf ( " حدث خطأ: %s % n " , e.getMessage ( ) ) ; } } }توفر لغة جافا أيضًا فئة داخلية (غير مدرجة رسميًا في مكتبة فئات جافا ) في الوحدة النمطيةjdk.unsupported ، sun.reflect.Reflectionوالتي تُستخدم بواسطة sun.misc.Unsafe. تحتوي هذه الفئة على دالة واحدة، للحصول على الفئة عن طريق إجراء استدعاء على عمق محدد. [ 12 ] وقد تم استبدال هذا الآن باستخدام الفئة ودالتها .staticClass<?>getCallerClass(intdepth)java.lang.StackWalker.StackFrameClass<?>getDeclaringClass()
جافا سكريبت، تايب سكريبت
المثال أدناه مكتوب بلغة جافا سكريبت وتايب سكريبت :
استيراد 'reflect-metadata' ؛// بدون استخدام الانعكاس const foo = new Foo (); foo.hello ( );// باستخدام الانعكاس const foo = Reflect.construct ( Foo ) ; const hello = Reflect.get ( foo , ' hello' ); Reflect.apply ( hello , foo , [ ] ) ;// باستخدام eval eval ( 'new Foo().hello()' );فيما يلي نفس المثال مكتوب بلغة TypeScript :
استيراد 'reflect-metadata' ؛// بدون استخدام الانعكاس const foo : Foo = new Foo (); foo . hello ();// باستخدام الانعكاس const foo : Foo = Reflect . construct ( Foo ); const hello : ( this : Foo ) => void = Reflect . get ( foo , 'hello' ) as ( this : Foo ) => void ; Reflect . apply ( hello , foo , []);// باستخدام eval eval ( 'new Foo().hello()' );جوليا
المثال أدناه مكتوب بلغة جوليا :
julia> struct Point x :: Int y end# فحص باستخدام الانعكاس julia> fieldnames ( Point ) (:x, :y)julia> fieldtypes ( Point ) (Int64, Any)julia> p = Point ( 3 , 4 )# الوصول باستخدام الانعكاس julia> getfield ( p , :x ) 3كوتلين
استخدام تقنية الانعكاس في جافا:
حزمة org.wikipedia.examplesاستيراد java.lang.reflect.Methodclass Foo { // ... constructor ()fun printHello () { println ( "Hello, world!" ) } }fun main ( args : Array < String > ) { // بدون استخدام الانعكاس val foo = Foo () foo . printHello ()// باستخدام الانعكاس try { // Foo::class.java يسترجع java.lang.Class<Foo> val reflectedFoo = Foo :: class . java . getDeclaredConstructor () . newInstance ()val m : Method = reflectedFoo . javaClass . getDeclaredMethod ( "printHello" )m.invoke ( reflectiveFoo ) } catch ( e : ReflectiveOperationException ) { System.err.printf ( " حدث خطأ : % s % n " , e.message ) } }باستخدام لغة كوتلين النقية:
حزمة org.wikipedia.examplesاستيراد kotlin.reflect.full.createInstance استيراد kotlin.reflect.full.functionsclass Foo { // ... fun printHello () { println ( "Hello, world!" ) } }fun main ( args : Array < String > ) { // بدون استخدام الانعكاس val foo = Foo () foo . printHello ()// باستخدام الانعكاس try { val kClass = Foo :: class val reflectedFoo = kClass . createInstance () val function = kClass . functions . first { it . name == "printHello" } function . call ( reflectedFoo ) } catch ( e : Exception ) { System . err . printf ( "حدث خطأ: %s%n" , e . message ) } }أوبجكتيف سي
المثال أدناه مكتوب بلغة Objective-C ، مما يعني استخدام إطار عمل OpenStep أو Foundation Kit :
// فئة Foo. @interface Foo : NSObject - ( void ) hello ; @end// إرسال "hello" إلى نسخة من Foo بدون استخدام الانعكاس. Foo * obj = [[ Foo alloc ] init ]; [ obj hello ];// إرسال "hello" إلى كائن من نوع Foo باستخدام الانعكاس. id obj = [[ NSClassFromString ( @"Foo" ) alloc ] init ]; [ obj performSelector : @selector ( hello )];بيرل
المثال أدناه مكتوب بلغة بيرل :
# بدون استخدام الانعكاس my $foo = Foo -> new ; $foo -> hello ;# أو Foo -> new -> hello ;# باستخدام الانعكاس my $class = "Foo" my $constructor = "new" ; my $method = "hello" ;my $f = $class -> $constructor ; $f -> $method ;# أو $class -> $constructor -> $method ;# مع eval eval "new Foo->hello;" ;PHP
المثال أدناه مكتوب بلغة PHP : [ 13 ]
// بدون استخدام الانعكاس $foo = new Foo (); $foo -> hello ();// باستخدام الانعكاس، باستخدام واجهة برمجة تطبيقات Reflections ، $reflector = new ReflectionClass ( "Foo" ); $foo = $reflector- > newInstance (); $hello = $reflector- > getMethod ( "hello" ); $hello- > invoke ( $foo );بايثون
المثال أدناه مكتوب بلغة بايثون :
من typing استورد Anyclass Foo : # ... def print_hello ( self ) -> None : print ( "Hello, world!" )إذا كان __name__ يساوي " __main__" : # بدون استخدام الانعكاس obj : Foo = Foo () obj.print_hello ( )# باستخدام الانعكاس obj : Foo = globals ()[ "Foo" ]() _ : Any = getattr ( obj , "print_hello" )()# باستخدام eval eval ( "Foo().print_hello()" )R
المثال أدناه مكتوب بلغة R :
# بدون استخدام الانعكاس، بافتراض أن الدالة foo() تُرجع كائنًا من نوع S3 يحتوي على الدالة "hello"، obj <- foo () hello ( obj )# باستخدام الانعكاس class_name <- "foo" generic_having_foo_method <- "hello" obj <- do.call ( class_name , list ()) do.call ( generic_having_foo_method , alist ( obj ))روبي
المثال أدناه مكتوب بلغة روبي :
# بدون استخدام الانعكاس obj = Foo.new obj.hello# باستخدام الانعكاس obj = Object.const_get ( " Foo " ) . new obj.send : hello# مع eval eval "Foo.new.hello"الصدأ
المثال أدناه مكتوب بلغة Rust (باستخدام وحدات الماكرو الإجرائية ).
// ماكرو أساسي يُسجّل سلسلة اسم دالة في استدعاء دالة فعلي macro_rules! invoke_method { ( $instance : expr , $method_name : expr ) => { match $method_name { "print_hello" => $instance . print_hello (), _ => eprintln! ( "حدث خطأ: لم يتم العثور على الدالة." ), } }; }struct Foo ;impl Foo { fn print_hello ( & self ) { println! ( "Hello, world!" ); } }fn main () { let foo = Foo ;// تسلسل الاستدعاء العادي foo.print_hello ( );// تسلسل على نمط الانعكاس عبر تعيين وقت الترجمة let method_to_call = "print_hello" ; invoke_method ! ( foo , method_to_call ); }سويفت
تعتمد تقنية الانعكاس السريع على القراءة فقط، وبالتالي فإن الاستدعاء الديناميكي ممكن فقط من خلال لغة Objective-C .
استيراد مؤسسةclass Foo : NSObject { @objc func printHello () { print ( "Hello, world!" ) } }class InvokeFooExample { static func main () { // بدون استخدام الانعكاس let foo = Foo () foo . printHello ()// باستخدام "الانعكاس" (وقت تشغيل Objective-C) let reflectedFoo = Foo ()let selector = #selector ( Foo . printHello )إذا استجاب reflectedFoo للمحدد ، فقم بتنفيذ reflectedFoo باستخدام المحدد .نظام الانعكاس في لغة Swift، مع Swift.Mirror، محدود النطاق بشكل كبير:
استيراد مؤسسةclass Foo { func printHello () { print ( "مرحباً بالعالم!" ) } }let foo = Foo ()let mirror = Mirror ( reflecting : foo )print ( type ( of : foo ) ) // Foo print ( mirror.children.count ) // الخصائص فقطزوجو
فيما يلي مثال باستخدام Xojo :
بدون استخدام الانعكاس، قم بإنشاء كائن جديد من نوع Foo باسم fooInstance . ثم قم بطباعة "مرحباً" (PrintHello).باستخدام الانعكاس، قم بتعريف متغيرات من نوع ` Introspection` ، مثل `classInfo` و` constructorInfo` و` fooInstance` . ثم قم بتعريف متغيرات من نوع `Introspection`، مثل `classInfo` و`constructorInfo`. بعد ذلك، قم بتعريف متغيرات من نوع ` Introspection` ، مثل ` constructorInfo` و` fooInstance` . ثم قم بتعريف متغيرات من نوع ` Introspection` ، مثل `methodInfo` و` methods` . بعد ذلك، قم بتكرار العملية على كل كائن من نوع ` Introspection` ، مثل `methodInfo` ، في كل دالة من دوال `methods` . إذا كان اسم الكائن `m` يساوي "PrintHello"، فقم باستدعاء الدالة ` fooInstance` من الكائن `m` . ثم قم بتكرار العملية على الكائن ` next`.انظر أيضاً
مراجع
الاقتباسات
- ↑ دليل تعليمي حول التفكير السلوكي وتطبيقه من تأليف جاك مالينفانت وآخرون (ملف PDF) ، غير معروف، مؤرشف من الأصل (ملف PDF) في 21 أغسطس 2017 ، تم استرجاعه في 23 يونيو 2019
- ↑ برايان كانتويل سميث، التفكير الإجرائي في لغات البرمجة ، قسم الهندسة الكهربائية وعلوم الحاسوب، معهد ماساتشوستس للتكنولوجيا، أطروحة دكتوراه، 1982.
- ↑ برايان سي. سميث. الانعكاس والدلالات في لغة إجرائية. مؤرشف في 13 ديسمبر 2015 على موقع Wayback Machine . تقرير فني MIT-LCS-TR-272، معهد ماساتشوستس للتكنولوجيا، كامبريدج، ماساتشوستس، يناير 1982.
- ↑ "CLHS: Function INTERN" . www.ai.mit.edu . تم الاطلاع عليه بتاريخ 27-03-2026 .
- ↑ "الدوال المدمجة" . وثائق بايثون . تم الاطلاع عليه بتاريخ 27-03-2026 .
- ↑ "eval() - JavaScript | MDN" . وثائق MDN على الويب . 21-01-2026 . تم الاطلاع عليه بتاريخ 27-03-2026 .
- ↑ باروس، باولو؛ جست، رينيه؛ ميلستين، سوزان؛ فاينز، بول؛ ديتل، فيرنر؛ داموريم، مارسيلو؛ إرنست، مايكل د. (أغسطس 2015). التحليل الثابت لتدفق التحكم الضمني: حل مشكلة انعكاس جافا ونوايا أندرويد (ملف PDF) (تقرير). جامعة واشنطن. UW-CSE-15-08-01 . تاريخ الاسترجاع: 7 أكتوبر 2021 .
- ↑ إيوفيدوم، إيو؛ ضوضاء القرص (5 أكتوبر 2021). "عشرون عامًا من الهروب من بيئة جافا المعزولة" . فراك . المجلد 10، العدد 46. تم الاسترجاع في 7 أكتوبر 2021 .
- 1 2 ميغيل غارسيا، فرانسيسكو أورتين. توصيف استخدام وتأثير الأداء لانعكاس جافا: دراسة تجريبية ، معاملات ACM في هندسة البرمجيات والمنهجية، 2026.
- ↑ تريستان سوليفين (1 مايو 2026). "انعكاس C++26: ما الذي يغيره فعليًا لقواعد البيانات الكبيرة؟" . wholetomato.com . هول توماتو.
- ↑ cppreference.com. "رأس المكتبة القياسية <meta /> (C++26)" . cppreference.com . cppreference.com . تم الاطلاع عليه بتاريخ 17 مايو 2026 .
- ↑ "Reflection (Java Platform SE 9)" . cr.openjdk.org . OpenJDK . تم الاطلاع عليه بتاريخ 10 أكتوبر 2025 .
- ↑ "PHP: ReflectionClass - Manual" . www.php.net .
مصادر
- جوناثان م. سوبيل ودانيال ب. فريدمان. مقدمة في البرمجة الموجهة نحو الانعكاس (1996)، جامعة إنديانا .
- تقنية مكافحة الانعكاس باستخدام لغة C# وواجهة سطر الأوامر C++ لمنع سرقة التعليمات البرمجية
للمزيد من القراءة
روابط خارجية
- التأمل في البرمجة المنطقية والوظيفية والموجهة للكائنات: دراسة مقارنة موجزة
- مقدمة في البرمجة الموجهة نحو الانعكاس
- صفحات برايان فوت حول التأمل في لغة سمول توك
- برنامج تعليمي حول واجهة برمجة تطبيقات Java Reflection من أوراكل
- بنى البرمجة
- مقارنات لغات البرمجة
