Delphi 泛型 class 用法编译错误
Delphi generic class usage compilation error
我正在为旧 Delphi XE 代码库编写一些实用程序代码;为了使事情更简单和更安全,我创建了一个方法,用于包装通过参数传递的特定类型 TProc<TReq>
(其中 TReq
是通用 class 类型) TProc<TObject>
稍后应该与 TClass(TReq)
和一个额外的字符串参数一起提供给第三方组件:
type
TREvoHostConnectionOptions = record
// [...]
procedure OnPush<TReq:class>(const pushMethod: string; const action: TProc<TReq>);
end;
// [...]
procedure TREvoHostConnectionOptions.OnPush<TReq>(const pushMethod: string; const action: TProc<TReq>);
var
rec: TRPushHandler;
begin
rec.PushMethod := pushMethod;
rec.PushModel := TClass(TReq);
rec.Handler :=
procedure(reqRawModel: TObject)
var
reqModel: TReq;
begin
// Conversione modello richiesta
reqModel := reqRawModel as TReq;
if Assigned(reqRawModel) and not Assigned(reqModel) then
raise EEvoHostException.Create(Format('Impossibile convertire il modello di tipo %s in %s.', [reqRawModel.ClassName, TClass(TReq).ClassName]));
// Azione
if Assigned(action) then
action(reqModel);
end;
PushHandlers.Add(rec);
end;
前面的方法编译成功,如果像这样调用,按预期工作(尽管将 TObject
作为泛型类型违背了该方法的目的):
opts.OnPush<TObject>('Test', procedure (reqModel: TObject) begin (* ... *) end);
但是,如果在测试表单单元中我使用特制模型调用它 class:
type
TTestModel = class(TObject)
strict private
_a, _b: string;
public
property A: string read _a write _a;
property B: string read _b write _b;
end;
我在调用单元中完全不相关的行(以及完全不同且完全不相关的方法)中收到以下编译器错误:
[DCC Error] WndMain.pas(96): E2010 Incompatible types: 'TTestModel' and 'TObject'
* 位移仅发生在这个特定错误中,如果我在同一文件的其他任何地方引入人为语法错误,它会在正确的行中报告。
有什么想法吗?这是编译器错误吗?如果是,有什么办法可以解决它吗?不幸的是,我无法删除方法上的 :class
约束,否则方法内部发生的 TClass(TReq)
转换会(逻辑上)引发另一个关于 TReq
不是约束 [=37] 的编译错误=] 或接口类型。
进一步调查,问题似乎是方法中的as
转换引起的,尽管它是在错误的文件中报告的。
这样改方法好像解决了:
procedure TREvoHostConnectionOptions.OnPush<TReq>(const pushMethod: string; const action: TProc<TReq>);
var
rec: TRPushHandler;
begin
rec.PushMethod := pushMethod;
rec.PushModel := TClass(TReq);
rec.Handler :=
procedure(reqRawModel: TObject)
var
reqModel: TReq;
begin
// Conversione modello richiesta
if Assigned(reqRawModel) and not reqRawModel.ClassType.InheritsFrom(rec.PushModel) then
raise EEvoHostException.CreateFmt('Impossibile convertire il modello di tipo %s in %s.', [reqRawModel.ClassName, rec.PushModel.ClassName]);
// Azione
if Assigned(action) then
action(TReq(reqModel));
end;
PushHandlers.Add(rec);
end;
我正在为旧 Delphi XE 代码库编写一些实用程序代码;为了使事情更简单和更安全,我创建了一个方法,用于包装通过参数传递的特定类型 TProc<TReq>
(其中 TReq
是通用 class 类型) TProc<TObject>
稍后应该与 TClass(TReq)
和一个额外的字符串参数一起提供给第三方组件:
type
TREvoHostConnectionOptions = record
// [...]
procedure OnPush<TReq:class>(const pushMethod: string; const action: TProc<TReq>);
end;
// [...]
procedure TREvoHostConnectionOptions.OnPush<TReq>(const pushMethod: string; const action: TProc<TReq>);
var
rec: TRPushHandler;
begin
rec.PushMethod := pushMethod;
rec.PushModel := TClass(TReq);
rec.Handler :=
procedure(reqRawModel: TObject)
var
reqModel: TReq;
begin
// Conversione modello richiesta
reqModel := reqRawModel as TReq;
if Assigned(reqRawModel) and not Assigned(reqModel) then
raise EEvoHostException.Create(Format('Impossibile convertire il modello di tipo %s in %s.', [reqRawModel.ClassName, TClass(TReq).ClassName]));
// Azione
if Assigned(action) then
action(reqModel);
end;
PushHandlers.Add(rec);
end;
前面的方法编译成功,如果像这样调用,按预期工作(尽管将 TObject
作为泛型类型违背了该方法的目的):
opts.OnPush<TObject>('Test', procedure (reqModel: TObject) begin (* ... *) end);
但是,如果在测试表单单元中我使用特制模型调用它 class:
type
TTestModel = class(TObject)
strict private
_a, _b: string;
public
property A: string read _a write _a;
property B: string read _b write _b;
end;
我在调用单元中完全不相关的行(以及完全不同且完全不相关的方法)中收到以下编译器错误:
[DCC Error] WndMain.pas(96): E2010 Incompatible types: 'TTestModel' and 'TObject'
* 位移仅发生在这个特定错误中,如果我在同一文件的其他任何地方引入人为语法错误,它会在正确的行中报告。
有什么想法吗?这是编译器错误吗?如果是,有什么办法可以解决它吗?不幸的是,我无法删除方法上的 :class
约束,否则方法内部发生的 TClass(TReq)
转换会(逻辑上)引发另一个关于 TReq
不是约束 [=37] 的编译错误=] 或接口类型。
进一步调查,问题似乎是方法中的as
转换引起的,尽管它是在错误的文件中报告的。
这样改方法好像解决了:
procedure TREvoHostConnectionOptions.OnPush<TReq>(const pushMethod: string; const action: TProc<TReq>);
var
rec: TRPushHandler;
begin
rec.PushMethod := pushMethod;
rec.PushModel := TClass(TReq);
rec.Handler :=
procedure(reqRawModel: TObject)
var
reqModel: TReq;
begin
// Conversione modello richiesta
if Assigned(reqRawModel) and not reqRawModel.ClassType.InheritsFrom(rec.PushModel) then
raise EEvoHostException.CreateFmt('Impossibile convertire il modello di tipo %s in %s.', [reqRawModel.ClassName, rec.PushModel.ClassName]);
// Azione
if Assigned(action) then
action(TReq(reqModel));
end;
PushHandlers.Add(rec);
end;