如何从 Delphi7 中的基本数据模块继承

How to Inherit from a base datamodule in Delphi7

我这样创建了一个基础数据模块:

unit dmi_Generic;
...
type
  TDMGenericClass = class of TdmiGeneric;

  TdmiGeneric = class(TDataModule)
private
  ReferencedForms: FormIDTypes;
public
  class procedure CloseDM(FormName: string; dm: TdmiGeneric);
  class function OpenDM(FormName: string; dm: TdmiGeneric; const dmClass:
                        TDMGenericClass): TdmiGeneric;
end;
...
class function TdmiGeneric.OpenDM(FormName: string; dm: TdmiGeneric; const
                dmClass: TDMGenericClass):
                TdmiGeneric;
var
    FormID: Integer;
begin
    FormID := GetFormID(FormName);
    if dm = nil then
        dm := dmClass.Create(nil);   //trouble is probably born here
    with dm do
        if not (FormID in ReferencedForms) then
            ReferencedForms := ReferencedForms + [FormID];
    Result := dm;
end;
...

我打算从 dmi_generic 继承其他数据模块,所以,在另一个单元中...

编辑1

uses
    dmi_Generic;
...
type
  TdmUserSecurity = class(TdmiGeneric)
... 
var
  dmUserSecurity: TdmUserSecurity;

在我的主要形式中...

uses
  UserSecurityDM;
  ...
procedure TfmMain.actUserManagerExecute(Sender: TObject);
begin
  dmUserSecurity := TdmUserSecurity.OpenDM(Self.Name,dmUserSecurity,TdmUserSecurity);
  //some code
  TdmUserSecurity.CloseDM(Self.Name,dmUserSecurity);
end;

编辑2: ...给出编译错误 "Incompatible type. 'TdmUserSecurity' and 'TdmiGeneric'"

我该如何正确解决这个问题?我是在主窗体中输入 return 值,还是应该在 dmi_generic 单元中更改某些内容? TIA

OpenDM() returns 一个 TdmiGeneric 指针。但是 dmUserSecurity 没有被声明为 TdmiGeneric,所以你会在这个赋值上得到一个错误:

dmUserSecurity := TdmUserSecurity.OpenDM(...);

你需要一个类型转换来解决这个问题,要么:

dmUserSecurity := TdmUserSecurity(TdmUserSecurity.OpenDM(...));

或:

dmUserSecurity := TdmUserSecurity.OpenDM(...) as TdmUserSecurity;

顺便说一句,为什么 OpenDM() 有一个 dm 参数?它在您显示的代码中没有用。您应该:

  1. 通过var传递它并摆脱Result

    unit dmi_Generic;
    ...
    type
      TdmiGeneric = class;
      TDMGenericClass = class of TdmiGeneric;
    
      TdmiGeneric = class(TDataModule)
      private
        ...
      public
        ...
        class procedure CloseDM(FormName: string; var dm: TdmiGeneric);
        class procedure OpenDM(FormName: string; const dmClass: TDMGenericClass; var dm: TDMGeneric);
      end;
    ...
    class procedure TdmiGeneric.OpenDM(FormName: string;  const dmClass: TDMGenericClass; var dm: TdmiGeneric);
    var
      ...
    begin
      ...
      if dm = nil then
        dm := dmClass.Create(nil);
      with dm do
        ...
    end;
    
    class procedure TdmiGeneric.CloseDM(FormName: string; var dm: TdmiGeneric);
    begin
      FreeAndNil(dm);
    end;
    

    uses
      UserSecurityDM;
    ...
    procedure TfmMain.actUserManagerExecute(Sender: TObject);
    begin
      TdmUserSecurity.OpenDM(Self.Name, TdmUserSecurity, TdmiGeneric(dmUserSecurity));
      //some code
      TdmUserSecurity.CloseDM(Self.Name, TdmiGeneric(dmUserSecurity));
    end;
    
  2. 摆脱作为参数的 dm 并将其声明为局部变量:

    unit dmi_Generic;
    ...
    type
      TdmiGeneric = class;
      TDMGenericClass = class of TdmiGeneric;
    
      TdmiGeneric = class(TDataModule)
      private
        ...
      public
        ...
        class procedure CloseDM(FormName: string; var dm: TDMGeneric);
        class function OpenDM(FormName: string; const dmClass: TDMGenericClass): TDMGeneric;
      end;
    ...
    class function TdmiGeneric.OpenDM(FormName: string; const dmClass: TDMGenericClass): TdmiGeneric;
    var
      dm: TDMGeneric;
      ...
    begin
      ...
      dm := dmClass.Create(nil);
      with dm do
        ...
      Result := dm;
    end;
    
    class procedure TdmiGeneric.CloseDM(FormName: string; var dm: TDMGeneric);
    begin
      FreeAndNil(dm);
    end;
    

    uses
      UserSecurityDM;
    ...
    procedure TfmMain.actUserManagerExecute(Sender: TObject);
    begin
      dmUserSecurity := TdmUserSecurity.OpenDM(Self.Name, TdmUserSecurity) as TdmUserSecurity;
      //some code
      TdmUserSecurity.CloseDM(Self.Name, TdmiGeneric(dmUserSecurity));
    end;
    

无论哪种方式,由于您是在 TdmUserSecurity class 而不是 TdmGeneric class 上调用 OpenDM(),您可以考虑使用 Self class 在 OpenDM() 里面输入,然后你可以去掉 dmClass 参数:

unit dmi_Generic;
...
type
  TdmiGeneric = class;
  TDMGenericClass = class of TdmiGeneric;

  TdmiGeneric = class(TDataModule)
  private
    ...
  public
    ...
    class procedure OpenDM(FormName: string; var dm: TdmiGeneric);
  end;
...
class procedure TdmiGeneric.OpenDM(FormName: string; var dm: TdmiGeneric);
var
  ...
begin
  ...
  if dm = nil then
  begin
    if Self = TdmiGeneric then
      raise Exception.Create('Must call OpenDM() on a descendant class type').
    dm := TDMGenericClass(Self).Create(nil);
  end;
  with dm do
    ...
end;

uses
  UserSecurityDM;
...
procedure TfmMain.actUserManagerExecute(Sender: TObject);
begin
  TdmUserSecurity.OpenDM(Self.Name, TdmiGeneric(dmUserSecurity));
  ...
end;

或:

unit dmi_Generic;
...
type
  TdmiGeneric = class;
  TDMGenericClass = class of TdmiGeneric;

  TdmiGeneric = class(TDataModule)
  private
    ...
  public
    ...
    class function OpenDM(FormName: string): TDMGeneric;
  end;
...
class function TdmiGeneric.OpenDM(FormName: string): TdmiGeneric;
var
  dm: TDMGeneric;
  ...
begin
  ...
  if Self = TdmiGeneric then
    raise Exception.Create('Must call OpenDM() on a descendant class type').
  dm := TDMGenericClass(Self).Create(nil);
  with dm do
      ...
  Result := dm;
end;

uses
  UserSecurityDM;
...
procedure TfmMain.actUserManagerExecute(Sender: TObject);
begin
  dmUserSecurity := TdmUserSecurity.OpenDM(Self.Name) as TdmUserSecurity;
  ...
end;