I created a base datamodule as such:
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;
...
I intended to inherit other datamodules from dmi_generic, so, in another unit...
Edit1
uses
dmi_Generic;
...
type
TdmUserSecurity = class(TdmiGeneric)
...
var
dmUserSecurity: TdmUserSecurity;
and in my main form...
uses
UserSecurityDM;
...
procedure TfmMain.actUserManagerExecute(Sender: TObject);
begin
dmUserSecurity := TdmUserSecurity.OpenDM(Self.Name,dmUserSecurity,TdmUserSecurity);
//some code
TdmUserSecurity.CloseDM(Self.Name,dmUserSecurity);
end;
Edit2: ...which gives compile error "Incompatible type. 'TdmUserSecurity' and 'TdmiGeneric'"
How do I fix this, properly? Do I typecast the return value at the main form, or is there something I should change at the dmi_generic unit? TIA
OpenDM()
returns a TdmiGeneric
pointer. But dmUserSecurity
is not declared as TdmiGeneric
, so you will get an error on this assignment:
dmUserSecurity := TdmUserSecurity.OpenDM(...);
You would need a type-cast to fix that, either:
dmUserSecurity := TdmUserSecurity(TdmUserSecurity.OpenDM(...));
Or:
dmUserSecurity := TdmUserSecurity.OpenDM(...) as TdmUserSecurity;
BTW, why does OpenDM()
have a dm
parameter at all? It is useless in the code you showed. You should either:
pass it by var
and get rid of 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;
get rid of dm
as a parameter and declare it as a local variable instead:
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;
Either way, since you are calling OpenDM()
on the TdmUserSecurity
class and not on the TdmGeneric
class, you might consider using the Self
class type inside of OpenDM()
, then you can remove the dmClass
parameter:
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;
Or:
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;