简体   繁体   English

如何使用类型类的类通用助手

[英]How to use a helper generic of type class of type

I am trying to figure out how to genericize this helper method; 我试图弄清楚如何对这个辅助方法进行泛化 ; so that it returns the same type that was asked for: 以便它返回与要求相同的类型:

type
    TScreenHelper = class helper for TScreen
    public
        function FindForm(DesiredFormClass: TFormClass): TForm;
    end;

Right now the caller has to cast the return value to type they already want: 现在,调用者必须将返回值强制转换为他们已经想要的类型:

var
   frmReportReminderSetup: TfrmReportReminderSetup;
begin
   //frmReportReminderSetup := Screen.FindForm(TfrmReportReminderSetup); Doesn't compile

   frmReportReminderSetup := TfrmReportReminderSetup(Screen.FindForm(TfrmReportReminderSetup));

The non-generic implementation is: 非通用实现是:

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;

Generics 泛型

What i want is some way to use generics so that the function returns the type it was asked for. 我想要的是一些使用泛型的方法,以便函数返回它所要求的类型。

frmContoso := Screen.FindForm(TfrmContoso);

In pseudo-code, the signature that i want would be something like: 在伪代码中,我想要的签名是这样的:

function FindForm(T: TFormClass): T;

When it comes time to turn this into actual Delphi syntax, i think you must specify one of the T references in angle brackets: 当需要将其转换为实际的Delphi语法时,我认为你必须在尖括号中指定一个T引用:

function FindForm(<T>): T;

But i don't think the 但我不认为 is allowed there; 允许在那里; i think it has to be before the opening parenthesis: 我认为它必须在前括号之前:

function FindForm<T>: T;

Try that 试试吧

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;

Except that fails to compile: 除了编译失败:

Result := nil;  E2010 Incompatible types: 'T' and 'Pointer'

I can sorta see what's wrong. 我可以看看有什么不对劲。 It doesn't understand that T is a class (ie what if it was an Integer ? Then it would absolutely be wrong to set it to nil .) 它不明白T是一个类(即如果它是一个Integer呢?那么将它设置为nil绝对是错误的。)

Constraints 约束

So i need to somehow give the compiler the hint of what type T will be: 所以,我需要以某种方式给编译器是什么类型的提示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;

This new signature is confusing to call; 这个新的签名令人困惑! you no longer pass a desired type to the function. 您不再所需类型传递给该函数。 Instead you now call a variation of the function that you want: 相反,你现在调用你想要的函数的变体:

frmContoso := Screen.FindForm<TfrmConsoto>();

But no matter; 但是不要紧; it's way of generics. 它是泛型的方式。

Except that's not valid 除非这是无效的

The syntax: 语法:

function FindForm<T: TFormClass>: T;

is not valid, as TFormClass is not one of the allowed Delphi constraint types: 无效,因为TFormClass不是允许的Delphi约束类型之一:

Constraints in Generics 泛型中的约束

Specifying Generics with Constraints 使用约束指定泛型

Constraint items include: 约束项包括:

  • Zero, one, or multiple interface types 零,一个或多个接口类型
  • Zero or one class type 零或一类类型
  • The reserved word "constructor", "class", or "record" 保留字“构造函数”,“类”或“记录”

(emphasis mine) (强调我的)

While i'm allowed one class type , i'm not passing a class type; 虽然我允许一种类型 ,但我没有传递类型; i'm passing a class of class type. 我正在传递一类课程类型。

So now i'm stuck. 所以现在我被卡住了。 In my attempt to save myself typing 25 characters, i've now blown an hour on the minutia of Delphi generics. 在我试图保存自己输入25个字符时,我现在已经在德尔福仿制药的细节上花了一个小时。

tl;dr TL;博士

How do i genericize : 如何泛化

function FindForm(DesiredFormClass: TFormClass): TForm;

Example non-working code 示例非工作代码

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.

Your constraint is wrong. 你的约束是错误的。 Instead of 代替

function FindForm<T: TFormClass>: T;

you need 你需要

function FindForm<T: TForm>: T;

You are going to instantiate this generic type with TMyForm rather than class of TMyForm . 您将使用TMyForm而不是class of TMyForm来实例化此泛型类型。

And you must only state the constraint in the declaration of the class and not in its implementation. 并且您必须仅在类的声明中声明约束,而不是在其实现中。 Here's a complete program that compiles: 这是一个完整的程序,编译:

{$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.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM