関数名を引数とする関数?

解決


lactone  2020-03-04 09:30:33  No: 148605

環境:Windows 10 Home、Delphi 10.3.2 Comm.ed.

呼び出される関数内で使われているすべての TFDQuery の Name property を得る関数が必要になりました。

今、
FDQuery1 を open している関数 func1 が、
FDQuery2 を open している関数 func2 を呼び出す、
二層の入れ子構造(?)になっている関数 func1 があるとします。

このとき、

showmessage( func3( func2 ) )が 'FDQuery2' を返し、
showmessage( func3( func1 ) )が 'FDQuery1,FDQuery2' を返す関数 func3 は、

どのように記述すればいいのでしょうか?
つまりは、再帰的に呼び出す関数名を引数とする関数の記述ということになるでしょか。


take  2020-03-04 09:58:32  No: 148606

質問や目的が2つ以上に見えるためそれぞれの回答しますが本当にやりたいことは別にあるような気がします。

1.呼び出される関数内で使われているすべての TFDQuery の Name プロパティを得る関数を作りたい
2.再帰的に呼び出す関数名を引数とする関数の記述方法が知りたい

1.Nameプロパティはともかく「関数内で使われているすべての TFDQuery」を得るには
その関数自身で使っているTFDQueryを返す仕組みを作るか、
TFDQueryの管理を共通クラスを使って管理させるかぐらいしか思いつきません。

2.「関数」ではなく「クラス」にして関数を呼び出す時にSelfを引数にすれば関数側で誰が呼んだか判断出来ます。
関数にこだわるんだったら関数の引数に呼ぶ側の名前を文字列かなにかで渡すことも可能ですが無駄が多いですね。


lactone  2020-03-04 12:33:20  No: 148607

質問が不明瞭になって申し訳ありません。

func1がFDQuery1を使っている関数(FDQuery2を使っているfunc2を含む)のとき、

procedure TForm1.Main;
var S:string;
begin
  FDQuery1.SQL.clear;
  FDQuery1.open('select * from [tabalename]');
  while not FDQuery1.eof do begin
       ・
     S:=func1;
       ・
       ・
    FDQuery1.next;
  end;
  FDQuery1.close
end;

この時、S:=func1;
でFDQuery1はcloseされていますので、procedure Mainはエラーを返します。
これを避けるために、func1でFDQuery1,FDQuery2が使われていることを、Main側でopen前に知りたいという訳です。

take様、十分な質問能力の不備を反省しております。
不明瞭な質問に対して示唆に富むsuggestionと解決への方向をご教示下さいまして、
ありがとうございます。

>TFDQueryの管理を共通クラスを使って管理させる~
>「関数」ではなく「クラス」にして関数を呼び出す時にSelfを引数にすれば~

「クラス」は理解の及んでいない領域ですので、これまでペストのように避けて通ってきましたが(笑)、
そうも言っていられないようです。


take  2020-03-04 13:19:34  No: 148608

複数回 openが呼ばれるとすでに openしているのでエラーになるので避けたいと言うことですね。

フラグで管理して専用の関数を用意するのが簡単かな

TForm1の上のほうにある private の下にフォーム内で使える変数
FOpened1 : Boolean;
FOpened2 : Boolean;

ブール型で定義しておいて

同じく4つ関数作って 2つ例で挙げるとこんな感じです。

procedure OpenQuery1();
  if not FOpened1 then begin
    FDQuery1.open('select * from [tabalename]');
    FOpened1 := True;
  end;
end;

procedure CloseQuery1();
begin
  FDQuery1.close;
  FOpened1 := False;
end;

と思って書いて気づきましたが

> showmessage( func3( func2 ) )が 'FDQuery2' を返し、
> showmessage( func3( func1 ) )が 'FDQuery1,FDQuery2' を返す関数 func3 は、
> どのように記述すればいいのでしょうか?

ここがなんか引っかかる

> これを避けるために、func1でFDQuery1,FDQuery2が使われていることを、Main側でopen前に知りたいという訳です。
Mainでopen前に if FOpened1 then で openしているかわかるけど

使われている?かどうかはプログラム書いた人じゃ無いとわかりません。

MainでFDQuery1を使っていてopen中の関数func1内でもFDQuery1使う必要があるんだったら
それはプログラム設計を見直しかと


lactone  2020-03-04 15:24:44  No: 148609

procedure TForm1.Main;
var S:string;
begin
  FDQuery1.SQL.clear;
  FDQuery1.open('select * from [tabalename]');
  while not FDQuery1.eof do begin
       ・
     S:=func1;
       ・
       ・
    FDQuery1.next;
  end;
  FDQuery1.close
end;

Main実行時、while~endループ内ではFDQuery1はopen状態である必要があるのですが、
S:=func1;
の次行ではFDQuery1はcloseの状態になります。
(func1ではFDQuery1.open後resultを得て、FDQuery1.closeしてから関数値を戻しますので)
従って、Mainに戻ったときではFDQuery1はcloseしているのに、
FDQuery1.next;
を実行するので、エラーになるのだと思っています。
ですから、MainでFDQuery1でなく、FDQuery3にかえれば、通してくれます。

Main内で、
procedure TForm1.Main;
var S:string;  Q:TFDQuery;
begin
 //ここでfunc1がFDQuery1,FDQuery2をopen,closeする関数であることを知ることがわかれば、
 //Q:=FDQuery3とできますので、
 Q:=FDQuery3;
  Q.SQL.clear;
  Q.open('select * from [tabalename]');
  while not Q.eof do begin
       ・
     S:=func1;
       ・
       ・
    Q.next;
  end;
  Q.close
end;

func1,func2でのFDQuery1,FDQuery12使用は固定していて、
呼び出し側で、動的にFDQuery3を得られるようにしたいのです。

ご指摘のとおり、skill上の点からプログラム設計に問題は山積状態と思われます。
何か基本的なところで、初歩的は思い込み違いがあることを憂慮します。


take  2020-03-04 16:02:48  No: 148610

> ですから、MainでFDQuery1でなく、FDQuery3にかえれば、通してくれます。

MainはFDQuery3使えば良いんじゃない?FDQuery3を使えない理由があるとか?

どうしてそうしないといけないのか?というのと、やろうとしていることをわかりやすく説明すると

・Mainはfunc1を呼び、func1は結果によってfunc2を呼ぶかも知れない
・Mainとfunc2ではFDQuery1を使用している

これを ifと forで例えるとこう

for i:= 0 to Count1 - 1 do begin
  for j:= 0 to Count2 - 1 do begin
    if Bool = True then begin
      for i:= 0 to Count3 - 1 do begin
      end;
    end;
  end;
end;

ループ変数 iが2回あるからうまく動作しないことに対して
「Bool = True になるときは 1行目の for で回す変数を iじゃなくて kにしたいのでそのやり方は?」
と質問されても困るんじゃないかな?


lactone  2020-03-04 16:38:25  No: 148611

take様、ありがとうございます。

ifとforの例えはよくわかります。
結局は
MainはFDQuery3使えば良いんじゃない?FDQuery3を使えない理由があるとか?
となることも了解致します。
これ以上の質問はprograming上の議論を超えてくる印象を持ちますので、
ここで解決と致します。

take様には貴重な時間を割いて頂き、有用なご指摘とご指導に対して、
無限の謝意を表します。
長い間、本当にありがとうございました。


AAA  2020-03-04 16:59:32  No: 148612

関数名を引数とする関数? は一応できるよ

procedure TForm1.X;
begin
    Caption := 'XXXX';
end;

function TForm1.Y: String;
begin
    RESULT := '22';
end;

function TForm1.Z(A:TFunc<String>): String;
begin
    Result := A;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
    P: TProc;
    F: TFunc<String>;
begin
    P := X;
    F := Y;

    P;

    Caption := Caption + F;
    Caption := Caption + Z(Y);

    Exit;
end;


lactone  2020-03-04 20:52:15  No: 148613

AAA様ありがとうございました。

が、難解で一口も消化できませんでした。
申し訳ありません。


※返信する前に利用規約をご確認ください。








  このエントリーをはてなブックマークに追加