是否可以将泛型类的后代移动到实现部分?

时间:2015-10-07 09:07:27

标签: delphi generics delphi-xe2

我想从接口部分清除具体类,但编译器不允许这样做。 是否有机会使外部代码无法解决具体的类?

unit Unit2;

interface

uses
  System.SysUtils
  , System.Generics.Collections
  , System.Win.Registry
  ;
type
  IMyRegistry<T> = interface
    procedure WriteValue(const Key, Ident: string; const AValue: T);
    function ReadValue(const Key, Ident: string; const ADefVal: T): T;
  end;

  TMyRegistry<T> = class abstract(TInterfacedObject, IMyRegistry<T>)
  strict private
    class var FDefaultReg: IMyRegistry<T>;
    class var FRegistry: TRegistry;
    class var FDefKey: string;
  private
    class function GetDefKey: string;
    class function GetInstance: IMyRegistry<T>; static;
  protected
    procedure WriteValue(const Key, Ident: string; const AValue: T); virtual; abstract;
    function ReadValue(const Key, Ident: string; const ADefVal: T): T; virtual; abstract;
    function GoToKey(const AKeyName: string; const ACreateKey: Boolean = False): Boolean;
    class property InnerRegistry: TRegistry read FRegistry;
  public
    class constructor Create;
    class destructor Destroy;
    class property Default: IMyRegistry<T> read GetInstance;
  end;

  TDefaultMyRegistry<T> = class(TMyRegistry<T>)
  protected
    procedure WriteValue(const Key, Ident: string; const AValue: T); override;
    function ReadValue(const Key, Ident: string; const ADefVal: T): T; override;
  end;

  TMyRegistryFactory = class
  public
    class function GetMyRegistryConcrete<T>: IMyRegistry<T>;
  end;

  //TMyRegInteger = class(TMyRegistry<Integer>)
  //protected
    //procedure WriteValue(const Key, Ident: string; const AValue: Integer); override;
    //function ReadValue(const Key, Ident: string; const ADefVal: Integer): Integer; override;
  //end;

  EMyRegGenericException = class(Exception);
    EMyRegTypeNotSupported = class(EMyRegGenericException);

const
  cCompanyName = 'MyCompany';
  cProgramName = 'MyProgram';

resourcestring
  SRegTypeNotSupported = 'Operations are not supported for values of type "%s"';

implementation

uses
  Winapi.Windows
  , System.TypInfo;

type
  TMyRegInteger = class(TMyRegistry<Integer>)
  protected
    procedure WriteValue(const Key, Ident: string; const AValue: Integer); override;
    function ReadValue(const Key, Ident: string; const ADefVal: Integer): Integer; override;
  end;    


{ TMyRegistry<T> }

class constructor TMyRegistry<T>.Create;
begin
  inherited;
  FDefaultReg := TDefaultMyRegistry<T>.Create;
  FRegistry := TRegistry.Create;
  FRegistry.RootKey := HKEY_CURRENT_USER;
  FDefKey := GetDefKey;
end;

class destructor TMyRegistry<T>.Destroy;
begin
  FreeAndNil(FRegistry);
  inherited;
end;

class function TMyRegistry<T>.GetDefKey: string;
const
  cDefKey = '\Software\%s\%s\';
begin
  Result := Format(cDefKey, [cCompanyName, cProgramName]);
end;

class function TMyRegistry<T>.GetInstance: IMyRegistry<T>;
begin
  Result := FDefaultReg;
end;

function TMyRegistry<T>.GoToKey(const AKeyName: string;  const ACreateKey: Boolean): Boolean;
var
  sDestKeyName: string;
begin
  sDestKeyName := FDefKey + AKeyName;
  Result := FRegistry.OpenKey(sDestKeyName, False);
  if not Result and ACreateKey then
    Result := FRegistry.OpenKey(sDestKeyName, ACreateKey);
end;


{ TDefaultMyRegistry<T> }

function TDefaultMyRegistry<T>.ReadValue(const Key, Ident: string;  const ADefVal: T): T;
var
  tmpReg: IMyRegistry<T>;
begin
  Assert(TypeInfo(T) <> nil, 'Тип не определен');
  Result := ADefVal;
  if GoToKey(Key) then
    if InnerRegistry.ValueExists(Ident) then
    begin
      tmpReg := TMyRegistryFactory.GetMyRegistryConcrete<T>;
      if Assigned(tmpReg) then
        Result := tmpReg.ReadValue(Key, Ident, ADefVal);
    end;
end;

procedure TDefaultMyRegistry<T>.WriteValue(const Key, Ident: string; const AValue: T);
var
  tmpReg: IMyRegistry<T>;
begin
  inherited;
  if GoToKey(Key, True) then
  begin
    tmpReg := TMyRegistryFactory.GetMyRegistryConcrete<T>;
    if Assigned(tmpReg) then
      tmpReg.WriteValue(Key, Ident, AValue);
  end;
end;


{ TMyRegistryFactory }

class function TMyRegistryFactory.GetMyRegistryConcrete<T>: IMyRegistry<T>;
begin
  Result := nil;
  if TypeInfo(T) = TypeInfo(Integer) then
    Result := IMyRegistry<T>(IMyRegistry<Integer>(TMyRegInteger.Create)) //<<<  [DCC Error] Unit2.pas(155): E2506 Method ...
  else
    raise EMyRegTypeNotSupported.CreateFmt(
      SRegTypeNotSupported, [PTypeInfo(TypeInfo(T))^.Name]);
end;


{ TMyRegInteger }

function TMyRegInteger.ReadValue(const Key, Ident: string;
  const ADefVal: Integer): Integer;
begin
  Result := InnerRegistry.ReadInteger(Ident);
end;

procedure TMyRegInteger.WriteValue(const Key, Ident: string; const AValue: Integer);
begin
  inherited;
  InnerRegistry.WriteInteger(Ident, AValue);
end;

end.

如果要将类声明“TMyRegInteger”移动到实现部分,则编译器会报告错误: “[DCC错误] Unit2.pas(155):E2506接口部分声明的参数化类型方法不得使用本地符号'.TMyRegInteger'”

in

class function TMyRegistryFactory.GetMyRegistryConcrete<T>: IMyRegistry<T>;
begin
  Result := nil;
  if TypeInfo(T) = TypeInfo(Integer) then
    Result := IMyRegistry<T>(IMyRegistry<Integer>(TMyRegInteger.Create)) //<<<<<

0 个答案:

没有答案