Jump to content
Ian Branch

I'm missing some nuance..

Recommended Posts

Hi Team,

I want to be able to make a generic function like this..

function SetDBSessionNames(const ComponentCount: Integer; const Components: TComponent; const sSessionName: string): boolean;
begin
  //
  for var i := 0 to ComponentCount - 1 do
  begin
    //
    if (Components[i] is TEDBSession) then (Components[i] as TEDBSession).SessionName := sSessionName;
    //
    if (Components[i] is TEDBDatabase) then (Components[i] as TEDBDatabase).SessionName := sSessionName;
    //
    if (Components[i] is TnlhTable) then (Components[i] as TnlhTable).SessionName := sSessionName;
    //
    if (Components[i] is TnlhQuery) then (Components[i] as TnlhQuery).SessionName := sSessionName;
    //
    if (Components[i] is TnlhScript) then (Components[i] as TnlhScript).SessionName := sSessionName;
    //
  end;
  //
end;

That would be called like this..

  //
  SetDBSessionNames(ComponentCount, Components, sSessionName);
//

The function is in a separate function library.

Unfortunately it doesn't like  "Components" in the if.... lines. 😞

I have obviously missed or misinterpreted some aspect.

Some assistance/guidance would be appreciated.

 

Regards & TIA,

Ian 

 

Share this post


Link to post

You are accessing variable 'Components' as if it where an array, but it is declared like a reference to a TComponent. I think you want to redeclare your function like:

type
TComponentArray = array of TComponent;
function SetDBSessionNames(const ComponentCount: Integer; const Components: TComponentArray; const sSessionName: string): boolean;

 

Share this post


Link to post

Tks Keesver.  That calms down the function itself, but now the calling function isn't happy

What replaces Components in the calling function?

SetDBSessionNames(ComponentCount, Components, sSessionName);

 

Share this post


Link to post

It looks like you want to use the component list of a TForm, so you should pass that form as a parameter:

 

function SetDBSessionNames(const AForm: TForm; const sSessionName: string): boolean;
begin
  //
  for var i := 0 to AForm.ComponentCount - 1 do
  begin
    //
    if AForm.Components[i] is TEDBSession then (AForm.Components[i] as TEDBSession).SessionName := sSessionName;
..

Then you can call it in the code of a form as

SetDBSessionNames(self, sSessionName);

 

Edited by Renate Schaaf

Share this post


Link to post

Hi Renate,

That looks like a winner but this..

SetDBSessionNames(Self, sSessionName);

Gives me this in this case..

Quote

[dcc32 Error] dmCurrent.pas(821): E2010 Incompatible types: 'TForm' and 'TdmC'

In this case it is a Datamodule the function is being called from.

 

Ian

 

Edit:  Solved - I made it an overload method and created one that use a TDataModule.

Edited by Ian Branch

Share this post


Link to post

Make it TComponent:

function SetDBSessionNames(AContainer: TComponent; const sSessionName: string): boolean;
begin
  //
  for var i := 0 to AContainer.ComponentCount - 1 do
  begin
    //
    var cmp := AContainer.Components[i];
    if cmp is TEDBSession then TEDBSession(cmp).SessionName := sSessionName;
    
    ...

 

Share this post


Link to post
2 minutes ago, Uwe Raabe said:

Make it TComponent:

Now we're getting fancy.  😉  But I like it.  🙂

 

Edited by Ian Branch

Share this post


Link to post
function SetDBSessionNames(const Components: array of TComponent; const sSessionName: string): boolean;

?

Share this post


Link to post
10 hours ago, Ian Branch said:

    //
    if (Components[i] is TEDBSession) then (Components[i] as TEDBSession).SessionName := sSessionName;
    //
    if (Components[i] is TEDBDatabase) then (Components[i] as TEDBDatabase).SessionName := sSessionName;
    //
    if (Components[i] is TnlhTable) then (Components[i] as TnlhTable).SessionName := sSessionName;
    //
    if (Components[i] is TnlhQuery) then (Components[i] as TnlhQuery).SessionName := sSessionName;
    //
    if (Components[i] is TnlhScript) then (Components[i] as TnlhScript).SessionName := sSessionName;
    //

 

Wow, that is just screaming for the SessionName to be moved into a common base class, or into a common interface that all of the components implement.

 

If the TEDB... and Tnlh... components are from different libraries, I would simply derive my own classes from them, and define my own interface, eg:

type
  IHaveASessionName = interface
    ['{6ea2f6fe-6b6f-4ea6-a893-12717e562329}']
    function GetTheSessionName: string;
    procedure SetTheSessionName(const Value: string);
    property TheSessionName read GetTheSessionName write SetTheSessionName;
  end;

...

type
  TMyEDBSession = class(TEDBSession, IHaveASessionName)
    function GetTheSessionName;
    procedure SetTheSessionName(const Value: string);  
  end;

function TMyEDBSession.GetTheSessionName;
begin
  Result := SessionName;
end;

procedure TMyEDBSession.SetTheSessionName(const Value: string); 
begin
  SessionName := Value;
end;

// And repeat for TEDBDatabase, TnlhTable, TnlhQuery, TnlhScript, etc...

...

for var i := 0 to ComponentCount - 1 do
begin
  var Intf: IHaveASessionName;
  if Supports(Components[i], IHaveASessionName, Intf) then
    Intf.TheSessionName := sSessionName;
end;

If the components are on DFMs at design-time, you can alternatively use interposer classes in the DFM units, eg:

type
  TEDBSession = class(edbcomps.TEDBSession, IHaveASessionName)
    function GetTheSessionName;
    procedure SetTheSessionName(const Value: string);  
  end;

// etc...

 

Edited by Remy Lebeau

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×