我想从接口部分清除具体类,但编译器不允许这样做。 是否有机会使外部代码无法解决具体的类?
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)) //<<<<<