2011-11-30 3 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; 
한 강력한 형식의 솔루션이 작동

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; 
공통 네임 스페이스를 제공하기 위해 다른 클래스에 모두 제네릭 클래스를 래핑하는 것입니다

+0

감사합니다. – gabr

+0

환영합니다. @ 가브리, 도와 드릴 수있어서 기쁩니다! –

4

사용법은 다음과 같습니다.

var 
    o: TObject; 
    i: IInterface; 

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

이것도 좋은 해결책입니다! –