2009-11-06 69 views
11

我曾在2010年德爾福使用泛型的開始,但我已經編譯這段代碼時,一個問題:爲什麼TGeneric <Base>和TGeneric <Descendant>不兼容的類型?

TThreadBase = class(TThread) 
... 
end; 

TThreadBaseList<T: TThreadBase> = class(TObjectList<T>) 
... 
end; 

TDataProviderThread = class(TThreadBase) 
... 
end; 

TDataCore = class(TInterfacedObject, IDataCore) 
private 
    FProviders: TThreadBaseList<TDataProviderThread>; 
... 
end; 

然後,我有一些嵌套的過程:

procedure MakeAllThreadsActive(aThreads: TThreadBaseList<TThreadBase>); 
begin 
... 
end; 

最後,我想打電話給在TDataCore類的代碼此嵌套過程:

MakeAllThreadsActive(FProviders); 

但是編譯器不希望編譯它,它說(」 <>」括號被取代 '()'):

[DCC錯誤] LSCore.pas(494):E2010不兼容的類型: 'TThreadBaseList(TThreadBase)' 和 'TThreadBaseList(TDataProviderThread)'

我不明白,雖然TDataProviderThread是TThreadBase的後裔。

我只好硬類型轉換來解決它:

MakeAllThreadsActive(TThreadBaseList<TThreadBase>(FProviders)); 

有誰知道爲什麼編譯器說這個錯誤?

+1

正如其他人已經解釋了爲什麼你得到這個錯誤,嘗試使MakeAllThreadsActive TThreadBaseList 的方法來解決它。 – 2009-11-06 14:27:39

回答

22

TDataProviderThread是TThreadBase的後代,但TThreadBaseList<TDataProviderThread>不是TThreadBaseList<TThreadBase>的後代。這不是繼承,它被稱爲協方差,雖然它看起來很直觀,但它不是,它必須單獨支持。目前,Delphi不支持它,儘管希望它能在未來的版本中發佈。

以下是協方差問題的基本原因:如果將它傳遞給的函數需要一個TThreadBase對象列表,並且將它傳遞給TDataProviderThread對象列表,那麼就沒有辦法阻止它調用。添加並粘貼一些其他的TThreadBase對象放入不是TDataProviderThread的列表中,現在你已經有了各種各樣的醜陋問題。你需要編譯器中的特殊技巧來確保不會發生這種情況,否則你會失去你的類型安全性。

編輯:這裏是給你一個可能的解決方案:請MakeAllThreadsActive到一個通用的方法,如:

procedure MakeAllThreadsActive<T: TThreadBase>(aThreads: TThreadBaseList<T>); 

或者你可以做什麼烏韋·拉貝建議。任何一個都可以工作。

+2

+1好的解釋,儘管我主要知道術語*協方差*主要來自方法。 – jpfollenius 2009-11-06 15:17:31

+2

如果你只是從對象中讀取數據,那麼它是一個**來源**,協方差是可以的。如果你正在寫新的價值觀,那麼你有一個**匯**,你想要反轉。如果它既是源又是匯(我們必須假設TObjectList 是,如果我們對它的任何方法沒有內在的知識),那麼你根本就不會有任何變化。用這個概念來編譯編譯器遠遠超出了「特殊技巧」。 – 2009-11-06 16:21:30

+1

我正在談論的特殊技巧包括向編譯器添加對協方差和相反性的支持,然後將TObjectList 的各個方法標記爲協變或反變換的安全方式,以便編譯器可以驗證它。 – 2009-11-06 17:07:03

6

類型

TList <TBase> 

不是不能用這種方式

TList <TChild> 

泛型的父類型。

相關問題