2011-06-03 63 views
4

我正在寫一個簡單的依賴注入/控制系統反轉基於TDictionary持有抽象類引用及其各自的實現者類。當類註冊完成該類構造函數時不會調用類構造函數

我的目標是:通過類型(顯然)

  • 避免直接實例化。
  • 在dpr中包含類的單元應該足以讓它註冊並通過di/ioc系統進行選擇和實例化。
  • 僅聲明實現部分中的具體實現類。
  • 使用類構造函數而不是初始化段。

順便說一句,我知道使用類構造函數來利用智能鏈接,並希望包含一個單位足以使一個類可用互相擊敗。我想用其他原因使用類構造函數而不是初始化部分。我想將所有的類初始化/註冊代碼放在一起,而不必在類構造函數和初始化部分之間進行分割。

問題

我希望類的登記進廠是在類的構造函數。不幸的是,編譯器並不認爲這個類是通過在它自己的類構造函數中使用它的類型而「感動」的。

當我將註冊函數放入初始化部分時,編譯器確實認爲該類被觸及並調用類​​構造函數。但是這樣做打破了我在類構造函數中保留所有類初始化代碼的對象。

兩個問題

  • 如果編譯器考慮自己的類的構造函數「觸摸班」使用類或者是太大的奢望編譯器做什麼?
  • 有沒有人有任何聰明的想法,我仍然可以實現我的目標,而不使用初始化部分?

抽象的應用程序中使用類:

TSite = class abstract (TObject) 
    function GetURL: string; virtual; abstract; 
    property URL: string read GetURL; 
end; 

TSites = class (TList<TSite>); 

TThisApplication = class abstract (TObject) 
    function Sites: TSites; virtual; abstract; 
end; 

具體的實現類(在實現部分聲明!)爲TThisApplication

TThisApplicationConcrete = class(TThisApplication) 
    class constructor ClassCreate; 
    strict private 
    FSites: TSites; 
    function Sites: TSites; override; 
    end; 

class constructor TThisApplicationConcrete.ClassCreate; 
begin 
    RegisterImplementorClass(TThisApplication, TThisApplicationConcrete); 
end; 

function TThisApplicationConcrete.Sites: TSites; 
var 
    SiteList: TSites; 
begin 
    if not Assigned(FSites) then begin 
    SiteList := TSites.Create; // Change to use factory 
    //RetrieveSites(SiteList); 
    FSites := SiteList; 
    end; 

    Result := FSites; 
end; 

的函數來獲取TThisApplication的實例:

function ThisApplication: TThisApplication; 
var 
    ImplementorClass: TClass; 
begin 
    ImplementorClass := GetImplementorClass(TThisApplication); 
    if Assigned(ImplementorClass) then begin 
    Result := ImplementorClass.Create as TThisApplication; 
    end else begin 
    Result := nil; 
    end; 
end; 

這是目前編碼在一個單獨的功能,但它瓦特/可移至工廠。

完整的示例代碼

如果有人想嘗試,我有我的可用的測試項目,在全碼:http://www.bjsoftware.com/delphistuff/stackoverdlow/classconstructors.zip

郵編內容:全部採用

  • 4個項目相同的源文件,只有條件定義不同(這就是爲什麼dproj也包括在內)
  • 4源文件
  • groupproj,並與所有4個項目DSK
  • RunTestApps.cmd運行所有4個項目
  • RESULTS.TXT與我的RunTestApps.cmd
  • WriteUp.txt的運行的輸出與該文本問題

請記住,在任何時候,你需要做一個「構建所有Projecs」,因爲所有的DCU的和exe的是要在源代碼目錄否則你要面對很多的錯誤和/或因爲EXE沒有做它的名字所表示的混淆。

+0

Uwe的和Allan的答案之間千鈞一髮。因爲類比而與Allan一起。它給了我一個我想要做的事情的生動畫面,讓我微笑...... – 2011-06-04 09:16:22

+0

Déjàvu:你不喜歡它,當你設計一個解決方案,它失敗了,因爲你做了一個隱含的假設,你甚至不知道你做了它:) – 2011-06-07 08:36:58

回答

8

這是預期的。正如Uwe指出的那樣,自引用類構造函數不足以觸發包含。將參考放在初始化部分將會執行這個技巧,因爲它不在類本身之內。嘗試自我引用一個類包含類似於試圖通過拉你自己的吊帶把自己拉出一個深洞。

+3

用於比喻。 – 2011-06-03 20:23:01

7

只要你不在類的任何地方使用這個類,編譯器會把它作爲根本不使用的類,因此不會調用類的構造函數。所以我想你必須使用初始化部分,而不是調整代碼來愚弄編譯器。採取務實的態度,而不是教條式的態度。無論如何,它會更具可讀性。

+1

是的,我的實用主義者已經在工作壓制教條主義。我想我需要外部確認。 – 2011-06-03 19:58:50

2

我認爲你期望類構造函數的工作方式不同於它的設計目的。類構造函數不會在第一次創建之前被調用。 (至少不在WIN32 delphi中)。如果一個類被引用,它的類構造函數將在之前運行該單元的初始化代碼。

如果您對您的類的唯一引用恰好在該類內部,那麼實際上鍊接到您的應用程序中的任何代碼都不會引用該類。因此,它的類構造函數將永遠不會被調用。

我相信寄存器函數屬於初始化部分。具有寄存器功能將強制類構造函數也被執行。我不明白你爲什麼要/要求把註冊碼放到類的構造函數中。

如果您想了解的方式類的構造函數/析構函數工作的詳細信息,您可以通過艾倫·鮑爾閱讀本相當不錯的文章:

http://blogs.embarcadero.com/abauer/2009/09/04/38899