将泛型与不同约束相结合

时间:2011-11-30 12:23:36

标签: delphi generics

我有这个原子乐观的初始化类:

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并相应地继续。

我不太喜欢这个想法,我正在寻找更好的方法。

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分: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);