Delphi 引用具有不同变量的例程

Delphi 引用具有不同变量的例程,delphi,Delphi,是否可能对单个例程有两个引用,即以某种方式组合这些引用: procedure SetUpGrid(AGrid: TStringGrid); procedure SetUpGrid(AGrid: TJVStringGrid); procedure SetUpGrid(AGrid: ??); Begin ... 将有两个过程,但这一个过程相同且冗长,只需要在其他过程中使用不同的网格。是的,如果两个过程都有公开所有所需功能的公共网格。即如果两者都是TCustomGrid的后代,则使用过程SetU

是否可能对单个例程有两个引用,即以某种方式组合这些引用:

procedure SetUpGrid(AGrid: TStringGrid);
procedure SetUpGrid(AGrid: TJVStringGrid);


procedure SetUpGrid(AGrid: ??);
Begin
...

将有两个过程,但这一个过程相同且冗长,只需要在其他过程中使用不同的网格。

是的,如果两个过程都有公开所有所需功能的公共网格。即如果两者都是
TCustomGrid
的后代,则使用
过程SetUpGrid(agid:TCustomGrid)

当然,由于所有对象都是从TObject派生出来的,所以您可以使用它,但它有些无用,因为TObject不会公开网格的任何属性/方法。。。您必须测试实际类型的输入,如

procedure SetUpGrid(AGrid: TObject);
begin
  if(AGrid is TStringGrid)then begin
     ...
  end else if(AGrid is TJVStringGrid)then begin
     ...
  end
end

这在某种程度上取消了只使用一个过程的想法。

如果TStringGrid和TJvStringGrid在某种程度上是“相关的”,即具有相同的基类,或者一个继承自另一个,那么它就相当简单。将该类型用作参数类型

如果不是这样,那就不那么容易了。泛型对您没有帮助,使用utmostbase类,TObject也没有任何帮助,因为它没有您需要的方法

解决方案一

您可能会幸运地使用匿名方法,并将这些方法用作函数的参数,以便可以在函数内部调用它们:

type
  TGridFunc = reference to function: Integer;

procedure SetupGrid(AGridFunc: TGridFunc);
var
  ...
begin
  ...
  Error := AGridFunc;
  ...
end;
您可以这样使用它:

var
  GF: TGridFunc;
  JvGrid: TJvStringGrid;
  VclGrid: TStringGrid;
begin
  ...
  SetupGrid(
    function: Integer
    begin
      ... do things with JvGrid ...
      Result := 0;
    end);

  SetupGrid(
    function: Integer
    begin
      ... do things with VclGrid ...
      Result := 1;
    end);

  ...
end;
这有点复杂,让人想起依赖注入,但我看不到其他方法

解决方案二

哦,等等,还有另一种方法:定义一个接口类型(比如说IStringGrid),它包含您可能需要的所有方法。实现两次,一次作为TJvStringGrid的后代,一次作为TStringGrid的后代,包装正确类型的现有网格。SetupGrid看起来像:

procedure SetupGrid(Grid: IStringGrid);
现在,您可以将这些实现传递给SetupGrid:

SetupGrid(TStringGridWrapper.Create(Form1.StringGrid1));

SetupGrid(TJvStringGridWrapper.Create(Form2.JvStringGrid1));
当然,只有当您可以重用这些包装器,或者如果SetupGrid非常复杂,您不想简单地编写两次,这才有意义。瞧,只要值得这么麻烦

更新 我刚刚检查过,显然TJvStringGrid继承自TJvExStringGrid,它继承自VCL中的TStringGrid。所以现在很容易:

procedure SetupGrid(AGrid: TStringGrid);
begin
  ...
  // things that equally apply to TStringGrid and TJvStringGrid can be done here. 
  if AGrid is TJvStringGrid then
  begin
    ...
    // things that only apply to TJvStringGrid can be done here.
    ...
  end;
  ...
end;

当然,TStringGrid和TJvStringGrid的单位必须同时位于该单位实施部分的uses子句或界面部分。

我怀疑TJvStringGrid
来自绝地VCL。在这种情况下,它是
TJvExStringGrid
的后代,TJvExStringGrid是
TStringGrid
的直接后代,当一个类(TJvStringGrid)从另一个类(TStringGrid)派生时,您无需执行任何特殊操作

您可以使用最常见的类(在本例中为TStringGrid)声明您的过程:

procedure SetUpGrid(AGrid: TStringGrid);
并将TJvStringGrid的一个实例传递给它

例如:

procedure SetUpGrid(AGrid: TStringGrid);
begin
  // Whatever your code does to set up the grid.
end;

procedure TForm1.SomeGridToSetup;
var
  ASimpleTStringGrid: TStringGrid;
  AJediVclStringGrid: TJvStringGrid;
begin
  ASimpleTStringGrid := TStringGrid.Create(Self);
  AJediVclStringGrid := TJvStringGrid.Create(Self);

  SetUpGrid(ASimpleTStringGrid);
  SetUpGrid(AJediVclStringGrid);
end;

我保留了原始内容,因为我认为其他解决方案适用于两个类不共享其祖先的情况。