delphi 反射(原理)


關於反射的用途是『降低模塊間的耦合度』這個倒未必盡然

單就delphi來說,從實現上看,它的所謂反射是基於RTTI,而RTTI的出現按照官方的說法是為了實現RAD中窗體文件DFM的持久化而產生的,其實也不是針對DFM文件或TForm啦,由於TPersistent在聲明的時候加上了{$M+},所以從TPersistent派生的對象都在編譯的時候添加了RTTI,而在TComponent中又增加了對TReader和TWriter支持,說的准確一點、時髦一點RTTI是為了實現對象的持久化和反持久化,在Delphi3之后加入了接口,從而將COM引入,而在delphi6以后又加入了對接口的RTTI的支持,從而將SOAP也引入到了delphi之中,從這兩個重大特性的加入上看到,除了Delphi對接口支持的越來越豐富,還有一點很重要的是Delphi很早就支持了遠程方法調用RPC,對於RPC的支持並不是簡單的對傳輸協議的支持,而是要在對象定義、編譯層面對其實現的支持。盡管COM的RPC與SOAP的RPC在表象上是有所不同的,但我們其實可以斷定,在Delphi6之后已經就可以對對象的方法動態調用了。事實上也確實如此,一切奧秘盡包含在TypInfo,IntfInfo,ObjAuto,Invoker這些單元之中,只可惜在Help中並沒有體現。我記得李維發過這樣一句嘆息,說其實在Borland實驗室中十年前就有很多天才很多很Cool的想法但是得不到老板的支持,最后只得痛惜離開Borland。我在翻看VCL代碼的時候,相信這確實是真的,現在很多在.NET或Java上很時髦的特性,有多少是Delphi在語言層面上是不支持的呢,我們忽略了Delphi是因為它們還沒有來得及被Borland的工程師推向前台、還沒來得及將其做成框架發布出來,而這些工程師就被趕跑了。

  可能是誤會了反射的意思,這里並不是指對另外單元中聲明的引用,而是指在運行時可以獲得代碼的特性以及在運行時可以改變它的行為。這樣說可能抽象一點,說的稍微形象一點,一般編譯型語言中,程序中所有定義的變量和函數,它們是否被使用、如何被使用,都是要在編碼的時候設定好全部的執行邏輯的,而運行時只是遵循其中一條或幾條執行路徑執行的,而所謂的反射就是要能夠在運行時通過一個外部的控制來決定程序內部的執行行為,也就是說從邏輯上看,程序不再是一個閉包的邏輯系統,而可以依賴於外部的注入。簡單的說程序的運行時結構是由許多代碼段、堆和棧這三種內存塊組成,而所謂的執行就是指內部邏輯可以訪問到代碼段中的所有定義,將函數代碼放在棧上展開執行,在堆中間分配所需空間以及一些其他的諸如IO訪問等行為的集合。所以,如果要實現外部的控制注入,即反射,至少需要滿足能夠訪問類似代碼段上數據而獲得變量和函數定義的部分,其次還要能夠控制函數在棧上展開執行。

     Delphi這種基於RTTI信息而實現的反射和Java、.Net有顯著的不同。由於Java、.Net是先將程序編譯成bytecode或CIL,在將中間代碼讓VM來執行,所以在這一類語言上實現反射的基本方式是獲得bytecode和CIL,這部分內容就類似於代碼段上的信息,然后外部注入的邏輯被重新編譯生成新的中間代碼后再讓VM執行,從而產生新的行為。在這種機制下,非但可以實現反射,而且還可以對中間代碼實行反編譯而獲得原始代碼。而Delphi對反射的實現和Java以及.Net有本質的不同,它將對象的字段和函數的信息編譯進RTTI,在編碼的時候將對象注冊進一個全局的列表中,運行時通過訪問該列表而獲得所需的對象,再從對象的RTTI中獲得字段和函數的信息,同時提供出一種可以在運行時執行對象方法的函數,也不需要再編譯,於是就間接的實現了反射機制。但是我們也應該注意到Delphi的反射和Java相比,首先是並不能反射到所有的變量和函數,例如全局的函數,靜態變量就不會獲得,其次由於不存在中間代碼,也不存在反編譯的問題,當然,這些都不是重點。其實這些東西在Delphi6\7的時候就已經有了,因為要支持SOAP,在SOAP標准中有一個SOAP的RPC表示,也就是說SOAP在調用遠程對象方法的時候,也就是通過字符串來驅動的,所以不但有對象的RTTI,也可以在聲明接口的 時候添加{$M+}來編譯進接口的RTTI,從而對接口方法也可以使用字符串來驅動。又因為最初的設計是針對SOAP的,所以在ObjAuto單元中ObjectInvoke方法不支持對象類型和指針類型,畢竟SOAP在遠程調用方法時傳物理地址是沒有意義的,當然,Variant也是不支持對象類型的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM