2010-10-23 125 views
1

這是我的other question的後續行動。模板(或其他技術)是否支持以下構造?

當我第一次聽說泛型時,它是在Delphi 2009發佈之前(他們首先介紹它的地方)。我知道它在.Net之前得到了支持,但我還沒有在這個領域挖掘。

閱讀泛型,我瞭解到它允許類給它一個變量參數,並且您傳遞給它的任何值都將被替換爲類的所有代碼。

的方式仿製藥進行了描述(或至少,我的理解泛型允許的)是,鑑於以下聲明:

procedure TMyClass<T>.Init; 
begin 
    FField := T.Create(nil); 
end; 

我認爲這是可行的。我以爲這裏編譯就會失敗情況如下:

begin 
    TMyClass<TComponent>.Create; //Works correctly 
    TMyClass<TObject>.Create; //Doesn't work, as even though it HAS a constructor, it has none that receive a single pointer parameter 
    TMyClass<string>.Create; //Doesn't work, not an object. 
end; 

現在,我清楚地知道我錯了。所以,現在我想知道,是否有支持這種構造的技術/語言特性。代碼模板也許?其他編程語言中的泛型?或者也許別的東西?

回答

1

現在,我清楚地知道我錯了。那麼,現在我想知道,是否有 技術/語言功能, 支持這樣的結構。代碼 模板也許?在其他 編程語言中的泛型?或者也許 別的東西?

C#中的泛型有你想要的能力。 C++中的模板甚至更強大 - 通過模板生成的代碼與手工編寫的代碼完全相同,除了它們只能在內部編譯的部分之外,這很吸引人。

+0

如果我錯了,糾正我,但C++中的模板具有在使用它的單元範圍內「定義」的缺點。因此,單位A.TMyClass 將與單位B.TMyClass 不兼容。對? – 2010-10-23 19:12:49

+0

在.NET中,在IL級別支持泛型和統一的輸入系統(所有東西,包括來自System.Object的值類型),所以.NET平臺上的幾乎所有語言(包括Delphi Prism,VB.NET和很多其他)同時支持,而不僅僅是C#。 – 2010-10-23 19:19:36

+0

@Ken:你錯了。 @Jeroen:那是真的。 C#確實有泛型,所以我沒有錯,但我可以更正確。 – Puppy 2010-10-23 19:23:14

0

您可以將約束放在泛型上。如果你想使用這種類型的某些方面,你需要這個。例如一種方法。

如果要調用構造函數,你需要給旁邊類約束的約束consructor:

type 
    TMyClass<T: TComponent, constructor> = class 
    // .. 
    end; 

procedure TMyClass<T>.Init; 
begin 
    FField := T.Create(nil); 
end; 

不幸的是TObject的是不是一個有效的約束。 (根據Delphi XE)。

現在,我很清楚我錯了。所以,現在我想知道,是否有支持這種構造的技術/語言>功能。代碼模板也許?其他>編程語言中的泛型?或者也許別的東西? 這可能是有風險的,甚至沒有意義。如果您致電通用方法X及你不支持方法X類實例化,什麼是正確的行爲...

+0

構造函數約束只允許呼籲參數的構造函數。即使將TComponent設置爲約束,也不允許調用TComponent的構造函數,因爲它有1個參數。 – 2010-10-23 19:08:41

1

@Gamecat,你不能有TObject作爲一個約束,但你可以有class作爲約束(這很好地涵蓋了缺少TObject約束)。

請注意,無論您使用的是TObject還是class,都無法使用無參數的參數調用Create

實施例1:class約束:

unit Unit1; 

interface 

uses 
    Classes; 

type 
    TMyClass<T: class, constructor> = class 
    strict private 
    FField: T; 
    public 
    procedure Init; 
    end; 

implementation 

procedure TMyClass<T>.Init; 
begin 
    FField := T.Create(); 
end; 

end. 

實施例2:TComponent作爲約束和參數在Create

unit Unit2; 

interface 

uses 
    Classes; 

type 
    TMyClass<T: TComponent, constructor> = class 
    strict private 
    FField: T; 
    public 
    procedure Init; 
    end; 

implementation 

procedure TMyClass<T>.Init; 
var 
    ComponentClass: TComponentClass; 
begin 
    ComponentClass := T; 
    FField := ComponentClass.Create(nil); 
end; 

end. 

除了class約束,也可以具有一個記錄約束。 有了這一點,你需要Default初始化字段:

unit Unit3; 

interface 

uses 
    Classes; 

type 
    TMyClass<T: record> = class 
    strict private 
    FField: T; 
    public 
    procedure Init; 
    end; 

implementation 

procedure TMyClass<T>.Init; 
begin 
    FField := Default(T); 
end; 

end. 

希望這揭示了仿製藥和約束的一些情況。

--jeroen

+0

我知道,但我看到(太遲)問題不在於如何使其工作,而是如果有語言允許構造(請參見最後一段)。 – 2010-10-23 19:12:33

+0

ComponentClass.Create(nil)爲+1;招。那真的是我的一天。非常好的解決方法是缺少適當的(或更多的進化)構造函數約束。 – 2010-10-23 19:18:32

+0

@Gamecat:我想知道原因,謝謝澄清。不用擔心,我自己常常不是一個「好問題的讀者」:-)注意我提出了兩個答案來解決問題的大部分內容。 – 2010-10-23 19:22:50

0

@Ken:爲了讓喜歡你的代碼要求在一個真正通用的方式來工作,你需要有一個統一的打字tystem該合併兩種引用類型(類)和值類型(字符串,整數等)。原生的Delphi沒有這樣的輸入系統(.NET有,Delphi Prism支持它,就像C#和VB.NET一樣)。

解決這個問題很困難; Allen Bauer gave it a shot implementing a Nullable type,他必須做一些嚴重的扭曲才能以涵蓋參考和值類型的方式實現等式(=)和NotEquals(<>)操作符行爲。

因此支持這些將是艱難的,但可能是可行的:

begin 
    TMyClass<TComponent>.Create; //Works correctly 
    TMyClass<TObject>.Create; //Doesn't work, as even though it HAS a constructor, it has none that receive a single pointer parameter 
    TMyClass<string>.Create; //Doesn't work, not an object. 
end; 

--jeroen