2011-11-30 146 views
6

我有這樣的原子樂觀初始化類仿製藥相結合:不同的約束

type 
    Atomic<T: IInterface> = class 
    type TFactory = reference to function: T; 
    class function Initialize(var storage: T; factory: TFactory): T; 
    end; 

class function Atomic<T>.Initialize(var storage: T; factory: TFactory): T; 
var 
    tmpIntf: T; 
begin 
    if not assigned(storage) then begin 
    tmpIntf := factory(); 
    if InterlockedCompareExchangePointer(PPointer(@storage)^, PPointer(@tmpIntf)^, nil) = nil then 
     PPointer(@tmpIntf)^ := nil; 
    end; 
    Result := storage; 
end; 

現在我想執行的對象相同的模式。

type 
    Atomic<T: class> = class 
    type TFactory = reference to function: T; 
    class function Initialize(var storage: T; factory: TFactory): T; 
    end; 

class function Atomic<T>.Initialize(var storage: T; factory: TFactory): T; 
var 
    tmpIntf: T; 
begin 
    if not assigned(storage) then begin 
    tmpIntf := factory(); 
    if InterlockedCompareExchangePointer(PPointer(@storage)^, PPointer(@tmpIntf)^, nil) = nil then 
     tmpIntf.Free; 
    end; 
    Result := storage; 
end; 

我可以在兩個不同的類中做這兩個,但我真的想把這兩個初始化器放在同一個傘下。 IOW,我理想喜歡用這個作爲

var 
    o: TObject; 
    i: IInterface; 

Atomic<TObject>.Initialize(o, CreateObject); 
Atomic<IInterface>.Initialize(i, CreateInterface); 

我找不到任何好的解決方案。我得到的唯一想法是聲明類爲Atomic<T>(沒有約束),然後以某種方式(不知道如何)在運行時檢查T的RTTI並相應地繼續。

我不太喜歡這個想法,我正在尋找更好的方法。

回答

4

看來你不能指定「類或接口」類型的約束。因此,最簡單的解決方案似乎是放棄約束(您可以使用RTTI在運行時強制執行它)。

對於RTTI的方法,你可以使用TypeInfo功能:

uses 
    ..., TypInfo;  

class function Atomic<T>.Initialize(var storage: T; factory: TFactory): T; 
var 
    tmpT: T; 
begin 
    if not assigned(PPointer(@storage)^) then begin 
    tmpT := factory(); 
    if InterlockedCompareExchangePointer(PPointer(@storage)^, PPointer(@tmpT)^, nil) = nil then begin 
     case PTypeInfo(TypeInfo(T))^.Kind of 
     tkInterface: 
      PPointer(@tmpT)^ := nil; 
     tkClass: 
      TObject(tmpT).Free; 
     else 
      raise Exception.Create('Atomic<T>.Initialize: Unsupported type'); 
     end; 
    end; 
    end; 
    Result := storage; 
end; 
+0

這似乎工作正常,謝謝! – gabr

+0

歡迎,@ gabr,我很高興能幫上忙! –

4

一個強類型的解決方案是兩個泛型類包裝成另一個類爲操作

type 
    Atomic = class 
    type 
     Intf<T: IInterface> = class 
     type TFactory = reference to function: T; 
     class function Initialize(var storage: T; factory: TFactory): T; 
     end; 
     Obj<T: class> = class 
     type TFactory = reference to function: T; 
     class function Initialize(var storage: T; factory: TFactory): T; 
     end; 
    end; 
提供公共的命名空間

用法於:

var 
    o: TObject; 
    i: IInterface; 

Atomic.Obj<TObject>.Initialize(o, CreateObject); 
Atomic.Intf<IInterface>.Initialize(i, CreateInterface); 
+0

這也是一個不錯的解決方案! –