我想弄清楚如何泛化这个帮助方法;以便它返回与要求相同的类型:
type
TScreenHelper = class helper for TScreen
public
function FindForm(DesiredFormClass: TFormClass): TForm;
end;
现在调用者必须将返回值强制转换为他们想要的类型:
var
frmReportReminderSetup: TfrmReportReminderSetup;
begin
//frmReportReminderSetup := Screen.FindForm(TfrmReportReminderSetup); Doesn't compile
frmReportReminderSetup := TfrmReportReminderSetup(Screen.FindForm(TfrmReportReminderSetup));
非通用实现是:
function TScreenHelper.FindForm(DesiredFormClass: TFormClass): TForm;
var
f: TForm;
i: Integer;
begin
Result := nil;
for i := 0 to Screen.FormCount-1 do //Screen.Forms does not support enumeration
begin
f := Screen.Forms[i];
if (f is DesiredFormClass) then
begin
Result := f;
Exit;
end;
end;
end;
我想要的是使用泛型的一些方法,以便函数返回它所要求的类型。
frmContoso := Screen.FindForm(TfrmContoso);
在伪代码中,我想要的签名就像:
function FindForm(T: TFormClass): T;
当需要将其转换为实际的Delphi语法时,我认为你必须在尖括号中指定一个 T 引用:
function FindForm(<T>): T;
但我不认为那里允许 ;我认为它必须在左括号之前:
function FindForm<T>: T;
TScreenHelper = class helper for TScreen
public
function FindFormOld(DesiredFormClass: TFormClass): TForm;
function FindForm<T>: T;
end;
function TScreenHelper.FindForm<T>: T;
var
f: TForm;
i: Integer;
begin
Result := nil;
for i := 0 to Screen.FormCount-1 do //Screen.Forms does not support enumeration
begin
f := Screen.Forms[i];
if (f is T) then
begin
Result := f as T;
Exit;
end;
end;
end;
除了编译失败:
Result := nil; E2010 Incompatible types: 'T' and 'Pointer'
我可以看看有什么不对劲。它不明白 T 是一个类(即如果它是Integer
怎么办?那么将它设置为nil
绝对是错误的。)
所以我需要以某种方式给编译器提供T
类型的提示:
TScreenHelper = class helper for TScreen
public
function FindForm<T: TFormClass>: T;
end;
function TScreenHelper.FindForm<T: TFormClass>: T;
var
f: TForm;
i: Integer;
begin
Result := nil;
for i := 0 to Screen.FormCount-1 do //Screen.Forms does not support enumeration
begin
f := Screen.Forms[i];
if (f is T) then
begin
Result := f as T;
Exit;
end;
end;
end;
这个新签名令人困惑!你不再传递所需类型的函数。相反,您现在调用您想要的功能的变体:
frmContoso := Screen.FindForm<TfrmConsoto>();
但无论如何;它是泛型的方式。
语法:
function FindForm<T: TFormClass>: T;
无效,因为TFormClass
不是允许的Delphi约束类型之一:
Constraints in Generics
使用约束指定泛型
约束条款包括:
- 零,一个或多个接口类型
- 零或一个班级类型
- 保留字“构造函数”,“类”或“记录”
(强调我的)
虽然我允许一个类型,但我没有传递类类型;我正在传递类类型。
所以现在我被卡住了。在我试图保存自己输入25个字符的时候,我现在已经在Delphi泛型的细节上花了一个小时。
我如何泛化:
function FindForm(DesiredFormClass: TFormClass): TForm;
program Project2;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, Vcl.Forms;
type
TScreenHelperCore = class(TObject)
public
class function FindForm<T: TForm>: T;
end;
TfrmContoso = class(TForm)
public
end;
{ TScreenHelperCore }
class function TScreenHelperCore.FindForm<T: TForm>: T;
// \__[dcc32 Error] Project2.dpr(23): E2029 ',', ';' or '>' expected but ':' found
var
f: TForm;
i: Integer;
begin
Result := nil;
for i := 0 to Screen.FormCount-1 do //Screen.Forms does not support enumeration
begin
f := Screen.Forms[i];
if (f is T) then
begin
Result := f;
Exit;
end;
end;
end;
var
f: TfrmContoso;
begin
try
f := TScreenHelperCore.FindForm<TfrmContoso>;
if f = nil then
f := TfrmContoso.Create(nil);
f.ShowModal;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
答案 0 :(得分:5)
你的约束是错误的。而不是
function FindForm<T: TFormClass>: T;
你需要
function FindForm<T: TForm>: T;
您将使用TMyForm
而不是class of TMyForm
来实例化此通用类型。
并且您必须仅在类的声明中声明约束,而不是在其实现中。这是一个完整的程序,编译:
{$APPTYPE CONSOLE}
uses
Vcl.Forms;
type
TScreenHelper = class helper for TScreen
public
function FindForm<T: TForm>: T;
end;
function TScreenHelper.FindForm<T>: T;
var
f: TForm;
i: Integer;
begin
for i := 0 to Screen.FormCount - 1 do
begin
f := Screen.Forms[i];
if (f is T) then
begin
Result := T(f);
Exit;
end;
end;
Result := nil;
end;
type
TMyForm = class(TForm)
end;
var
Form: TMyForm;
begin
Form := Screen.FindForm<TMyForm>;
end.