リフレクションプログラミング

ウィキペディアから、無料の百科事典
ナビゲーションにジャンプ 検索にジャンプ

コンピュータサイエンスではリフレクションプログラミングまたはリフレクションは、プロセスが自身の構造と動作を調べ、内省し、変更する機能です。[1]

歴史的背景

初期のコンピューターは、ネイティブのアセンブリ言語でプログラムされていました。これらの元のアーキテクチャは、命令をデータとして定義し、自己変更コードを使用することでプログラムできるため、本質的にリフレクション[要出典]でした。プログラミングの大部分がAlgolCobolFortranPascalCなどの高レベルのコンパイル言語に移行すると、型システムにリフレクションが組み込まれた新しいプログラミング言語が登場するまで、このリフレクティブ機能はほとんどなくなりました。[要出典]

Brian Cantwell Smithの1982年の博士論文では、手続き型プログラミング言語での計算リフレクションの概念と、3-Lispのコンポーネントとしてのメタサーキュラーインタープリターの概念が紹介されました。[2] [3]

を使用します

リフレクションは、プログラマーがデータを表示したり、さまざまな形式のデータを処理したり、通信用のデータのシリアル化または逆シリアル化を実行したり、コンテナーまたは通信のバースト用にデータのバンドルおよびアンバンドリングを実行したりするための汎用ソフトウェアライブラリを作成するのに役立ちます

リフレクションを効果的に使用するには、ほとんどの場合、計画が必要です。設計フレームワーク、エンコーディングの説明、オブジェクトライブラリ、データベースのマップ、またはエンティティの関係。

リフレクションは、言語をネットワーク指向のコードにより適したものにします。たとえば、Javaなどの言語が、シリアル化、バンドル、およびさまざまなデータ形式のライブラリを有効にすることで、ネットワークで適切に動作するのを支援します。Cなどのリフレクションのない言語は、 Abstract Syntax Notationなどのタスクに補助コンパイラを使用して、シリアル化とバンドル用のコードを生成する必要があります。

リフレクションは、実行時にプログラムの実行を監視および変更するために使用できますリフレクション指向のプログラムコンポーネントは、コードのエンクロージャーの実行を監視し、そのエンクロージャーの目的に応じて自身を変更できます。これは通常、実行時にプログラムコードを動的に割り当てることによって実現されます。

Javaなどのオブジェクト指向プログラミング言語では、リフレクションを使用すると、コンパイル時にインターフェイス、フィールド、メソッドの名前を知らなくても、実行時にクラス、インターフェイス、フィールド、およびメソッドを検査できます。また、新しいオブジェクトのインスタンス化とメソッドの呼び出しも可能です。

リフレクションは、モックオブジェクトの実行時の作成/インスタンス化など、ソフトウェアテストの一部としてよく使用されます。

リフレクションは、メタプログラミングの重要な戦略でもあります。

C#Javaなどの一部のオブジェクト指向プログラミング言語では、リフレクションを使用してメンバーのアクセシビリティルールをバイパスできます。C#プロパティの場合、これは、非公開プロパティの(通常は非表示の)バッキングフィールドに直接書き込むことで実現できます。クラスと型の非公開メソッドを見つけて手動で呼び出すこともできます。これは、プロジェクト内部ファイルだけでなく、.NETのアセンブリやJavaのアーカイブなどの外部ライブラリでも機能します。

実装

リフレクションをサポートする言語は、実行時に利用できる多くの機能を提供しますが、そうでなければ、低レベルの言語では実現するのが困難です。これらの機能のいくつかは、次の機能です。

これらの機能は、さまざまな方法で実装できます。MOOでは、リフレクションは日常のプログラミングイディオムの自然な部分を形成します。動詞(メソッド)が呼び出されると、 verb(呼び出される動詞の名前)やthis (動詞が呼び出されるオブジェクト)などのさまざまな変数が入力され、呼び出しのコンテキストが示されます。セキュリティは通常、プログラムで呼び出し元スタックにアクセスすることによって管理されます。呼び出し元)は、現在の動詞が最終的に呼び出されたメソッドのリストであるため、呼び出し元()[0](元のユーザーによって呼び出されたコマンド)でテストを実行すると、不正使用から身を守るための動詞。

コンパイルされた言語は、ランタイムシステムに依存して、ソースコードに関する情報を提供します。たとえば、コンパイルされたObjective-C実行可能ファイルは、実行可能ファイルのブロックにすべてのメソッドの名前を記録し、プログラムにコンパイルされた基になるメソッド(またはこれらのメソッドのセレクター)に対応するテーブルを提供します。Common Lispなどの関数のランタイム作成をサポートするコンパイル言語では、ランタイム環境にコンパイラーまたはインタープリターが含まれている必要があります。

プログラム変換システムを使用して自動ソースコード変更を定義する ことにより、リフレクションが組み込まれていない言語にリフレクションを実装できます。

セキュリティに関する考慮事項

リフレクションにより、ユーザーはアプリケーションを介して予期しない制御フローパスを作成し、セキュリティ対策をバイパスする可能性があります。これは、攻撃者によって悪用される可能性があります。[4]安全でないリフレクションによって引き起こされたJavaの過去の脆弱性により、信頼できない可能性のあるリモートマシンから取得したコードがJavaサンドボックスセキュリティメカニズムから抜け出すことができました。2013年の120のJava脆弱性に関する大規模な調査では、安全でないリフレクションがJavaで最も一般的な脆弱性であると結論付けられましたが、最も悪用されているわけではありません。[5]

次のコードスニペットは、クラスのインスタンス fooを作成し、そのメソッドを呼び出しますプログラミング言語ごとに、通常の呼び出しシーケンスとリフレクションベースの呼び出しシーケンスが表示されます。 Foo PrintHello

C#

以下はC#の例です:

//リフレクションなし
Foofoo = new Foo  ); foo PrintHello ();   


//リフレクション
オブジェクトを使用 foo  =  Activator CreateInstance "complete.classpath.and.Foo" ); 
MethodInfo  method  =  foo GetType ()。GetMethod "PrintHello" ); 
メソッド呼び出すfoo  null );

Delphi / Object Pascal

このDelphi / Object Pascalの例は、TFooクラスがUnit1と呼ばれるユニットで宣言されていることを前提としています。

 RTTI  Unit1を使用します;

 反射なしの手順; 
var 
  Foo  TFoo ; 
Foo := TFooを開始します
  作成; Fooを試してくださいこんにちは; 最後にFoo 無料; 終了; 終了;  
  
    
  
    
  


手順 WithReflection ; 
var 
  RttiContext  TRttiContext ; 
  RttiType  TRttiInstanceType ; 
  Foo  TObject ; 
RttiType := RttiContextを開始します
  FindType 'Unit1.TFoo' as TRttiInstanceType ; Foo := RttiType GetMethod 'Create' Invoke RttiType。MetaclassType [ ] AsObject ;    
     
  
    RttiTypeを試してくださいGetMethod 'Hello' 呼び出すFoo  []); 
  最後に
    Foo 無料; 
  終了; 
終了;

eC

以下はeCの例です。

//リフレクションなし
Foofoo { } ;   
foo こんにちは();

//リフレクション
クラスを使用fooClass = eSystem_FindClass __ thisModule "Foo" );    
インスタンスfoo = eInstance_New fooClass );   
メソッドm = eClass_FindMethod fooClass "hello" fooClass .module ;     
((void * )())(void * m .function foo );  

に移動

以下はGoの例です:

 「リフレクト」をインポート

//反射なし
f  :=  Foo {} 
f こんにちは()

//リフレクション
ありfT  :=  reflect TypeOf Foo {})
fV  :=  reflect 新規fT 

m  :=  fV MethodByName "Hello " 
ifm  IsValid (){ m nil )を呼び出す} 
    

Java

以下はJavaの例です。

import  java.lang.reflect.Method ;

//リフレクションなし
Foofoo = new Foo  ); foo こんにちは();   


//リフレクションを使用して
{ Objectfoo = Fooを試して くださいクラスnewInstance ();
       

    メソッド m  =  foo getClass ()。getDeclaredMethod "hello"  new  Class <?> [ 0 ] ); 
    m 呼び出すfoo ); 
}  catch  ReflectiveOperationException は無視されます) {}

JavaScript

以下はJavaScriptの例です。

//リフレクションなし
constfoo =  new Foo foo  こんにちは()  


//リフレクションを
使用constfoo  = Reflect  構築Foo const hello = Reflect get foo 'hello' Reflect 適用hello foo []) 
    
  

// eval 
evalを使用'new Foo()。hello()' 

ジュリア

以下は、Julia(プログラミング言語)の例です。

julia>  struct  Point 
           x :: Int 
           y 
       end

#リフレクション
ジュリアによる検査> フィールド名ポイント
(:x、:y)

julia >  fieldtypes Point 
(Int64、Any)

 ジュリア> p  = ポイント3、4 _

#リフレクションによるアクセス
julia>  getfield p  :x 
3

Objective-C

以下はObjective-Cの例であり、 OpenStepまたはFoundationKitフレームワーク のいずれかが使用されていることを意味します。

// Fooクラス。
@interface  Foo  :NSObject
-  void hello ;
@終わり

//リフレクションなしでFooインスタンスに「hello」を送信します。
Foo * obj = [[ Foo alloc ] init ];     
[ obj hello ]; 

//リフレクションを使用してFooインスタンスに「hello」を送信します。
id obj = [[ NSClassFromString @ "Foo" alloc ] init ];     
[ obj PerformSelector @selector hello )];  

Perl

以下はPerlの例です:

#リフレクションなし
でmy  $ foo  =  Foo- > new ; 
$ foo- > hello ;

#または
Foo- > new- > hello ;

#リフレクションを使用し
て、my  $ class  =  "Foo" 
my  $コンストラクター =  "new" ; 
私の $ method  =  "hello" ;

私の $ f  =  $ class- > $コンストラクター; 
$ f- > $ method ;

#または
$ class- > $コンストラクター-> $ method ;


#eval eval  " new Foo-> hello;"を使用 ;

PHP

以下はPHPの例です。

//リフレクションなし
$ foo  =  new  Foo (); 
$ foo- > hello ();

//リフレクションを使用し、ReflectionsAPIを使用
$ reflector  =  new  ReflectionClass 'Foo' ); 
$ foo  =  $ reflector- > newInstance (); 
$ hello  =  $ reflector- > getMethod 'hello' ); 
$ hello- > invoke $ foo );

Python

以下はPythonでの例です:

#反射なし
obj  =  Foo ()
obj こんにちは()

#リフレクションあり
obj  =  globals ()[ "Foo" ]()
getattr obj  "hello" )()

#eval 
evalを使用"Foo()。hello()" 

R

以下はRの例です:


#リフレクションなしで、 foo ()がメソッド "hello" obj  < -foo  ()hello obj を持つS3タイプのオブジェクトを返すと仮定します


#リフレクション
ありclass_name  <-  "foo" 
generic_having_foo_method  <-  "hello" 
obj  <  -do.call class_name  list ())
do.call generic_having_foo_method  alist obj ))

ルビー

以下はRubyの例です。

#反射なし
obj  =  Foo 新しい
オブジェクトこんにちは

#リフレクションあり
class_name  =  "Foo" 
method_name  =  :hello 
obj  =  Object const_get class_name 新しい
オブジェクトmethod_nameを送信します 

#evaleval 「 
Foo.new.hello  」を使用

Xojo

以下はXojoを使用した例です:

'
リフレクションなしDimfooInstance  As New FoofooInstance PrintHello   


'
内省としての反射DimclassInfoを 使用 Typeinfo = GetTypeInfo Foo DimコンストラクターAsIntrospection ConstructorInfo = classInfo GetConstructors Dim fooInstance As Foo =コンストラクター0 )。内省としてDimメソッド()を呼び出します。MethodInfo = classInfo それぞれGetMethods   
     
     
     
  m 内省として MethodInfoInメソッドIfm _ _ Name = "PrintHello " Thenm Invoke fooInstance End If Next  
      
    
   

も参照してください

参考文献

引用

  1. ^ Jacques Malenfant etal。による行動反射とその実装に関するチュートリアル。 (PDF) 、不明、 2017年8月21日にオリジナル (PDF)からアーカイブ、2019年6月23日に取得
  2. ^ Brian Cantwell Smith、プログラミング言語の手続き的考察、電気工学およびコンピュータサイエンス学部、マサチューセッツ工科大学、博士論文、1982年。
  3. ^ ブライアンC.スミス。手続き型言語でのリフレクションとセマンティクス WaybackMachineで2015年12月13日にアーカイブされました。テクニカルレポートMIT-LCS-TR-272、マサチューセッツ工科大学、ケンブリッジ、マサチューセッツ、1982年1月。
  4. ^ バロス、パウロ; ただ、ルネ。ミルスタイン、スザンヌ; ブドウの木、ポール; ディーテル、ヴェルナー; d'Amorim、マルセロ; Ernst、Michael D.(2015年8月)。暗黙の制御フローの静的分析:JavaリフレクションとAndroidインテントの解決(PDF)(レポート)。ワシントン大学。UW-CSE-15-08-01 2021年10月7日取得
  5. ^ Eauvidoum、Ieu; ディスクノイズ(2021年10月5日)。「Javaサンドボックスからの脱出の20年」Phrack10、いいえ。46 2021年10月7日取得{{cite magazine}}:CS1 maint:作成者パラメーターを使用します(リンク

ソース

さらに読む

  • Ira R. Forman and Nate Forman、Java Reflection in Action(2005)、ISBN 1-932394-18-4 
  • Ira R.FormanおよびScottDanforth、メタクラスを機能させる(1999)、ISBN 0-201-43305-2 

外部リンク