オブジェクト指向【言語別】呼び出し元情報を取得する方法まとめ

オブジェクト指向でプログラミングをしていると、メソッドや関数の呼び出し元の情報がほしいと感じることがまれにある。

そこで、いくつかの言語で、呼び出し元のメソッド名を取得する方法についてまとめてみた。

紹介する言語は、Ruby, C#, Java, JavaScript。個人的によく使うという理由で、この4言語にした。

結論から言ってしまうと、Ruby, C#, Javaでは、呼び出し元のクラス名やメソッド名などの、名前情報を調べることはできるが、呼び出し元のオブジェクトを取得することはできない。

それに対してJavaScriptは、呼び出し元オブジェクトを取得することが可能なことが可能だった。しかし推奨されない機能で、今後使えなくなる可能性が高い。

Rubyで呼び出し元のメソッド名を取得する方法

実行結果:

study01.rb:5:in call'
study01.rb:15:in
<main>’

Kernel.callerを使うことで、呼び出し元のメソッド名を取得している。

(Kernel.callerについての説明はRuby 1.9.3 リファレンスマニュアル Kernelモジュールが参考になると思う。)

C#で呼び出し元のメソッド名を取得する方法

 

実行結果:

class name: StudyCppLang.BeCalled, method name: Void beCalled()
class name: StudyCppLang.Caller, method name: Void call()
class name: StudyCppLang.Program, method name: Void Main(System.String[])
class name: System.AppDomain, method name: Int32 _nExecuteAssembly(System.Reflec
tion.RuntimeAssembly, System.String[])
class name: System.AppDomain, method name: Int32 ExecuteAssembly(System.String,
System.Security.Policy.Evidence, System.String[])
class name: Microsoft.VisualStudio.HostingProcess.HostProc, method name: Void Ru
nUsersAssembly()
class name: System.Threading.ThreadHelper, method name: Void ThreadStart_Context
(System.Object)
class name: System.Threading.ExecutionContext, method name: Void Run(System.Thre
ading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean
)
class name: System.Threading.ExecutionContext, method name: Void Run(System.Thre
ading.ExecutionContext, System.Threading.ContextCallback, System.Object)
class name: System.Threading.ThreadHelper, method name: Void ThreadStart()

StackFrameは呼び出し階層についての文字列情報を保持するクラス。

ここに目を付ければ、あとは正規表現などで加工すれば、メソッド名だけ取得するといったことなども可能。

Javaで呼び出し元のメソッド名を取得する方法

(動作させてみるなら適切な位置にファイルを作って動作させてみてください。)

意図的にThrowableインスタンスを作成して、getStackTrace()メソッドを呼び出すことで、呼び出し元のクラス名やメソッド名を調べている。

細かい点は、やはりJava API のThrowableが参考になると思う。

JavaScriptは呼び出し元のオブジェクトが取得できる

Ruby, C#, Javaなどは、呼び出し元のクラス名やメソッド名などの名前情報を取得するのがせいいっぱいだった。

ところがJavaScriptの場合は、呼び出し元の関数を参照することが可能。

実行結果:

 

arguments.callee.callerで、呼び出し元のオブジェクトが取得できている。

 

ここで少し、arguments.callee.callerを有意義に利用した例を紹介する。

Sampleインスタンスのa変数に、4回にわたり2を掛けて、表示するというプログラム。

4行目の

とすると、出力結果は「32」ではなく「2」になり、非常に残念な結果になってしまう。

thisが参照するオブジェクトが、SampleインスタンスではなくNumberインスタンスになってしまうことが原因だ。

このように、一見便利に見えるcallee.callerだが、非推奨で今後廃止される可能性が高いため、使用は控えたほうがよさそう、というのが実情だ。

どんでん返しだけど、呼び出し元情報なんて本当は必要無い。

今回の記事は、呼び出し元の情報を取得できるといいな~という思いもあって、調べてみたところから始まりました。

しかし結果は、ほとんどの言語が、呼び出し元の情報を取得するような機能は備えておらず、今回紹介した言語の中で唯一それを備えていたJavaScriptでさえ、非推奨であり、廃止予定になっている。

なぜだと思いますか?

 

多分それは、正しいプログラミングには、呼び出し元の情報を知る必要は無いから。

オブジェクト指向であれば、呼び出されたメソッドは、そのメソッドを超えて影響しないところに、カプセル化の意味がある。

もしその枠を超えた影響を与えたいのであれば、それはグローバルな変数にして明示的に、外部からアクセスしてもいいことを主張すればいい。

 

JavaやC#で呼び出し元情報を取得する方法を調べているときに、ひょっとしたら呼び出し元を取得できるかもしれない方法についての情報も、実はあるにはあった。

でも、その方法は、reflectionを使う等、言語として気軽に使えるものではなく、意図的に簡単には呼び出し元情報にはアクセスできないようにしているように感じた気さえする。

 

きっとそれは、それぞれの言語の根源に、正しいプログラミング(特にオブジェクト指向)には、呼び出し元の情報を知る必要は無いという思いがあるからなのではないかと思う。

コメントを残す

トラックバック: http://pgnote.net/wp-trackback.php?p=5