Un langage prenant en charge la réflexion offre un certain nombre de fonctionnalités disponibles à l'exécution qui seraient difficiles à mettre en œuvre dans un langage de bas niveau. Parmi ces fonctionnalités, on peut citer :
Ces fonctionnalités peuvent être implémentées de différentes manières. En programmation orientée objet ( MOO) , la réflexion fait partie intégrante du langage de programmation courant. Lors de l'appel de verbes (méthodes), diverses variables, telles que verble nom du verbe appelé et thisl'objet sur lequel il est appelé, sont initialisées afin de fournir le contexte de l'appel. La sécurité est généralement gérée par l'accès programmatique à la pile d'appel : cette pile contenant callers()la liste des méthodes ayant finalement appelé le verbe courant, l'exécution de tests sur callers()[0]la commande invoquée par l'utilisateur initial permet au verbe de se protéger contre toute utilisation non autorisée.
Les langages compilés s'appuient sur leur environnement d'exécution pour obtenir des informations sur le code source. Un exécutable Objective-C compilé , par exemple, enregistre les noms de toutes les méthodes d'un bloc, fournissant une table permettant de les associer aux méthodes sous-jacentes (ou aux sélecteurs de ces méthodes) compilées dans le programme. Dans un langage compilé prenant en charge la création de fonctions à l'exécution, tel que Common Lisp , l'environnement d'exécution doit inclure un compilateur ou un interpréteur.
La réflexion peut être implémentée pour les langages dépourvus de réflexion intégrée en utilisant un système de transformation de programmes pour définir des modifications automatisées du code source.
Exemples
Les extraits de code suivants créent une instanceclasseméthodelangage de programmation , les séquences d'appel classiques et par réflexion sont présentées.
Common Lisp
Voici un exemple en Common Lisp utilisant le système d'objets Common Lisp :
( defclass foo () ()) ( defmethod print-hello (( f foo )) ( format T "Bonjour de ~S~%" f ));; Normal, sans réflexion ( let (( foo ( make-instance 'foo ))) ( print-hello foo ));; Par réflexion, rechercher la classe nommée « foo » et la méthode ;; nommée « print-hello » qui se spécialise sur « 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
La réflexion n'est pas possible en C , bien que certaines parties de la réflexion puissent être émulées.
#include <stdio.h> #include <stdlib.h> #include <string.h>typedef struct { // ... } Foo ;typedef void ( * Méthode )( void * );// La méthode : Foo::printHello void Foo_printHello ( void * _ ) { printf ( "Bonjour, monde ! " ); }// Type de structure de table de méthodes simulée { const char * nom ; Méthode fn ; } MethodEntry ;const MethodEntry FOO_METHODS [] = { { "printHello" , Foo_printHello }, { NULL , NULL } // Sentinelle pour marquer la fin };// Simuler la recherche de méthode par réflexion Method 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 () { // Sans réflexion Foo foo ; Foo_printHello ( & foo );// Avec réflexion émulée Foo * reflected = ( Foo * ) malloc ( sizeof ( Foo )); if ( ! reflected ) { fprintf ( stderr , "Échec de l'allocation mémoire " ); return EXIT_FAILURE ; }const char * nom = "printHello" ; Méthode m = trouverMethodByName ( nom );if ( m ) { m ( reflected ); } else { fprintf ( stderr , "Méthode '%s' introuvable " , name ); free ( reflected ); return EXIT_FAILURE ; }libre ( réfléchi ) ; retourner EXIT_SUCCESS ; }
C++
Voici un exemple en C++ (utilisant la réflexion ajoutée dans C++26 ).
import std ;using std :: string_view ; using std :: views :: filter ; using std :: meta :: access_context ; using std :: meta :: exception ; using std :: meta :: info ;espace de noms 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 ; } } // Note: this is std::meta::exception, not std::exception throw exception ( std :: format ( "Échec de la récupération de la méthode {} du type {}" , 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 ) } ); }classe Foo { privé : // ... public : Foo () = par défaut ;void printHello () const { std :: println ( "Bonjour, monde !" ); } };int main ( int argc , char * argv []) { Foo foo ;// Sans réflexion foo . printHello ();// Avec réflexion auto invokePrint = [ : createInvoker ( ^^ Foo , "printHello" ) : ]; invokePrint ( foo );retourner 0 ; }
C#
Voici un exemple en C# :
espace de noms Wikipedia.Exemples ;using System ; using System.Reflection ;classe Foo { // ...public void PrintHello () { Console.WriteLine ( " Bonjour, monde !" ) ; } }public class InvokeFooExample { static void Main ( string [] args ) { // Sans réflexion Foo foo = new (); foo . PrintHello ();// Avec réflexion Object reflectedFoo = Activator.CreateInstance ( typeof ( Foo ) ); MethodInfo method = reflectedFoo.GetType () . GetMethod ( " PrintHello " ) ; method.Invoke ( foo , null ) ; } }
Delphi, Object Pascal
Cet exemple Delphi et Object Pascal suppose qu'une classe TFoo a été déclarée dans une unité appelée Unit1 :
utilise RTTI , Unité 1 ;procédure SansRéflexion ; var Foo : TFoo ; début Foo := TFoo . Créer ; essayer Foo . Bonjour ; enfin Foo . Libérer ; fin ; fin ;procédure AvecRéflexion ; var RttiContext : TRttiContext ; RttiType : TRttiInstanceType ; Foo : TObject ; début RttiType := RttiContext . FindType ( 'Unit1.TFoo' ) as TRttiInstanceType ; Foo := RttiType . GetMethod ( 'Create' ) . Invoke ( RttiType . MetaclassType , []) . AsObject ; essayer RttiType . GetMethod ( 'Hello' ) . Invoke ( Foo , []) ; finalement Foo . Free ; fin ; fin ;
eC
Voici un exemple en eC :
// Sans réflexion Foo foo {}; foo . hello ();// Avec réflexion Class fooClass = eSystem_FindClass ( __thisModule , "Foo" ); Instance foo = eInstance_New ( fooClass ); Method m = eClass_FindMethod ( fooClass , "hello" , fooClass . module ); (( void ( * )())( void * ) m . function )( foo );
Aller
Voici un exemple en Go :
importer ( "fmt" "reflect" )type Foo struct {}func ( f Foo ) Hello () { fmt . Println ( "Bonjour, monde !" ) }func main ( ) { // Sans réflexion var f Foo f.Hello ( )// Avec réflexion var fT reflect.Type = reflect.TypeOf ( Foo { } ) var fV reflect.Value = reflect.New ( fT )var m reflect.Value = fV.MethodByName ( " Bonjour " )if m.IsValid ( ) { m.Call ( nil ) } else { fmt.Println ( " Méthode introuvable " ) } }
Java
Voici un exemple en Java :
paquet org.wikipedia.examples ;import java.lang.reflect.Method ;classe Foo { // ...public void printHello ( ) { System.out.println ( " Bonjour, monde ! " ) ; } }public class InvokeFooExample { public static void main ( String [] args ) { // Sans réflexion Foo foo = new Foo (); foo . printHello ();// Avec réflexion, essayez { Foo reflectedFoo = Foo . class . getDeclaredConstructor () . newInstance ();Méthode m = reflectedFoo.getClass () . getDeclaredMethod ( "printHello" , new Class < ?>[ 0 ] ) ; m.invoke ( reflectedFoo ) ; } catch ( ReflectiveOperationException e ) { System.err.printf ( " Une erreur s'est produite : % s % n " , e.getMessage ( ) ) ; } } }
Java fournit également une classe interne (non officiellement incluse dans la bibliothèque de classes Java ) dans le modulejdk.unsupported `java.json` , sun.reflect.Reflectionutilisée par ` java.json` sun.misc.Unsafe. Elle contient une méthode `get` permettant d'obtenir la classe effectuant un appel à une profondeur spécifiée. Cette classe est désormais remplacée par la classe `java.json` et sa méthode ` get` .staticClass<?>getCallerClass(intdepth)java.lang.StackWalker.StackFrameClass<?>getDeclaringClass()
JavaScript/TypeScript
Voici un exemple en JavaScript :
importer 'reflect-metadata' ;// Sans réflexion const foo = new Foo (); foo.hello ( );// Avec réflexion const foo = Reflect.construct ( Foo ); const hello = Reflect.get ( foo , ' hello' ) ; Reflect.apply ( hello , foo , [ ] ) ;// Avec eval eval ( 'new Foo().hello()' );
Voici le même exemple en TypeScript :
importer 'reflect-metadata' ;// Without reflectionconstfoo:Foo=newFoo();foo.hello();// With reflectionconstfoo:Foo=Reflect.construct(Foo);consthello:(this:Foo)=>void=Reflect.get(foo,'hello')as(this:Foo)=>void;Reflect.apply(hello,foo,[]);// With evaleval('new Foo().hello()');
Julia
The following is an example in Julia:
julia>structPointx::Intyend# Inspection with reflectionjulia>fieldnames(Point)(:x, :y)julia>fieldtypes(Point)(Int64, Any)julia>p=Point(3,4)# Access with reflectionjulia>getfield(p,:x)3
Kotlin
Using Java reflection:
packageorg.wikipedia.examplesimportjava.lang.reflect.MethodclassFoo{// ...constructor()funprintHello(){println("Hello, world!")}}funmain(args:Array<String>){// Without reflectionvalfoo=Foo()foo.printHello()// With reflectiontry{// Foo::class.java retrieves a java.lang.Class<Foo>valreflectedFoo=Foo::class.java.getDeclaredConstructor().newInstance()val m : Méthode = reflectedFoo . javaClass . getDeclaredMethod ( "printHello" )m.invoke ( reflectedFoo ) } catch ( e : ReflectiveOperationException ) { System.err.printf ( " Une erreur s'est produite : % s % n " , e.message ) } }
Utilisation de Kotlin pur :
package org.wikipedia.examplesimport kotlin.reflect.full.createInstance import kotlin.reflect.full.functionsclass Foo { // ... fun printHello () { println ( "Bonjour, monde !" ) } }fun main ( args : Array <String> ) { // Sans réflexion val foo = Foo ( ) foo.printHello ( )// Avec réflexion 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 ( "Une erreur s'est produite : %s%n" , e . message ) } }
Objectif-C
Voici un exemple en Objective-C , impliquant l' utilisation du framework OpenStep ou Foundation Kit :
// Classe Foo. @interface Foo : NSObject - ( void ) hello ; @end// Envoi de « hello » à une instance de Foo sans réflexion. Foo * obj = [[ Foo alloc ] init ]; [ obj hello ];// Envoi de « hello » à une instance de Foo par réflexion. id obj = [[ NSClassFromString ( @"Foo" ) alloc ] init ]; [ obj performSelector : @selector ( hello )];
Perl
Voici un exemple en Perl :
# Sans réflexion, mon $foo = Foo -> nouveau ; $foo -> bonjour ;# ou Foo -> nouveau -> bonjour ;# Par réflexion, ma $class = "Foo" ma $constructeur = "new" ; ma $méthode = "hello" ;mon $f = $class -> $constructeur ; $f -> $méthode ;# ou $classe -> $constructeur -> $méthode ;# avec eval eval "new Foo->hello;" ;
PHP
Voici un exemple en PHP :
// Sans réflexion $foo = new Foo (); $foo- > hello ();// Avec réflexion, en utilisant l'API Reflections $reflector = new ReflectionClass ( "Foo" ); $foo = $reflector -> newInstance (); $hello = $reflector -> getMethod ( "hello" ); $hello -> invoke ( $foo );
Python
Voici un exemple en Python :
from typing import Anyclasse Foo : # ... def print_hello ( self ) -> None : print ( "Bonjour, monde !" )if __name__ == "__main__" : # Sans réflexion obj : Foo = Foo () obj . print_hello ()# Avec réflexion obj : Foo = globals ()[ "Foo" ]() _ : Any = getattr ( obj , "print_hello" )()# Avec eval eval ( "Foo().print_hello()" )
R
Voici un exemple en R :
# Sans réflexion, en supposant que foo() renvoie un objet de type S3 possédant la méthode "hello" obj <- foo () hello ( obj )# Avec réflexion class_name <- "foo" generic_having_foo_method <- "hello" obj <- do.call ( class_name , list ()) do.call ( generic_having_foo_method , alist ( obj ))
Rubis
Voici un exemple en Ruby :
# Sans réflexion , obj = Foo.new obj.hello# Avec réflexion obj = Object.const_get ( " Foo " ) . new obj.send : hello# Avec eval eval "Foo.new.hello"
Rouiller
Voici un exemple en Rust (utilisant des macros procédurales ).
// Une macro de base qui associe une chaîne de caractères représentant le nom d'une méthode à un appel de méthode réel. macro_rules! invoke_method { ( $instance : expr , $method_name : expr ) => { match $method_name { "print_hello" => $instance . print_hello (), _ => eprintln! ( "Une erreur s'est produite : Méthode introuvable." ), } }; }struct Foo ;impl Foo { fn print_hello ( & self ) { println! ( "Bonjour, monde !" ); } }fn main () { let foo = Foo ;// Séquence d'appel normale foo . print_hello ();// Séquence de style réflexion via un mappage à la compilation let method_to_call = "print_hello" ; invoke_method ! ( foo , method_to_call ); }
Rapide
La réflexion Swift est en lecture seule, et l'invocation dynamique n'est donc possible que via Objective-C .
Fondation d'importationclass Foo : NSObject { @objc func printHello () { print ( "Bonjour, monde !" ) } }class InvokeFooExample { static func main () { // Sans réflexion let foo = Foo () foo . printHello ()// Avec la « réflexion » (environnement d'exécution Objective-C) , soit reflectedFoo = Foo ()let selector = #selector ( Foo . printHello )si reflectedFoo.respond ( à : selector ) { reflectedFoo.perform ( selector ) } } }
Le système de réflexion de Swift, avec Swift.Mirror, est beaucoup plus limité dans sa portée :
Fondation d'importationclass Foo { func printHello () { print ( "Bonjour, monde !" ) } }soit foo = Foo ()soit miroir = Miroir ( réfléchissant : foo )print ( type ( of : foo ) ) // Foo print ( mirror.children.count ) // Propriétés uniquement
Xojo
Voici un exemple utilisant Xojo :
' Sans réflexion Dim fooInstance As New Foo fooInstance . PrintHello' Avec réflexion Dim classInfo As Introspection.Typeinfo = GetTypeInfo ( Foo ) Dim constructors ( ) As Introspection.ConstructorInfo = classInfo.GetConstructors Dim fooInstance As Foo = constructors ( 0 ) .Invoke Dim methods ( ) As Introspection.MethodInfo = classInfo.GetMethods For Each m As Introspection.MethodInfo In methods If m.Name = " PrintHello " Then m.Invoke ( fooInstance ) End If Next