powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
16 сообщений из 16, страница 1 из 1
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39668463
Инсомниа
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Есть некоторое множество функций. Функции чужие и их самих корректировать не получится. Функции эти имеют одно общее - они возвращают код ошибки (ну или успех).
В большинстве случаев надо вызывать ряд функций друг за другом, но продолжать только если у предыдущих был успех.
А также было бы крайне хорошо получать информацию на каком именно "шаге" (и по возможности в какой функции) возникла проблема.

Можно городить жуткую лестницу:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
FuncResult:=FuncA(a, b, c, ...);
if FuncResult=GoodResult then
    begin
    FuncResult:=FuncB(1, 2, 3, ...);
    if FuncResult=GoodResult then
        begin
        FuncResult:=FuncC(@a, -2, 'test', ...);
        if FuncResult=GoodResult then
            begin
            ...
                  ... ShowMessage('Done!');
            end
        else
            ShowMessage('Error on step 3, in function FuncC, with error code '+FuncResult);
        end
    else
        ShowMessage('Error on step 2, in function FuncB, with error code '+FuncResult);
    end
else
    ShowMessage('Error on step 1, in function FuncA, with error code '+FuncResult);


Можно городить подряд, но с кучей проверок и досрочными выходами:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
FuncResult:=FuncA(a, b, c, ...);
if FuncResult<>GoodResult then
    begin
    ShowMessage('Error on step 1, in function FuncA, with error code '+FuncResult);
    exit;
    end;
FuncResult:=FuncB(1, 2, 3, ...);
if FuncResult<>GoodResult then
    begin
    ShowMessage('Error on step 2, in function FuncB, with error code '+FuncResult);
    exit;
    end;
FuncResult:=FuncC(@a, -2, 'test', ...);
if FuncResult<>GoodResult then
    begin
    ShowMessage('Error on step 3, in function FuncC, with error code '+FuncResult);
    exit;
    end;
...
ShowMessage('Done!');


А если у меня "цепочка" не из трёх, а их трёх десятков функций? И мне может понадобится их оперативно менять или переставлять местами или временно закоментировать какие-то?

Не оборачивать же каждую чужую функцию чтоб бросала исключение? Полагаю будет как-то неудобно и затратно... Нужна какая-то общая обёртка или какой-то совершенно иной подход...
Подскажите пожалуйста - что-то можно попробовать?


Пока крутится на уме а не попытаться ли соорудить что-то подобное:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
SequentialSteps.Call(@FuncA, [a, b, c, ...]);
SequentialSteps.Call(@FuncB, [1, 2, 3, ...]);
SequentialSteps.Call(@FuncC, [@a, -2, 'test', ...]);
...
if SequentialSteps.Failed then
    ShowMessage('Error on step '+SequentialSteps.Step+', in function '+SequentialSteps.Func+', with error code '+SequentialSteps.Error);
else
    ShowMessage('Done!');

Но ума не приложу как такое реализовать...
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39668467
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИнсомниаА также было бы крайне хорошо получать информацию на каком именно "шаге" (и по возможности
в какой функции) возникла проблема.

Если избавиться от этого желания, то можно написать так:
Код: sql
1.
Result := FuncA() and FuncB() and FuncC();


Если не избавляться, то так:
Код: sql
1.
2.
3.
if not FuncA then raise Exception.Create('FuncA error');
if not FuncB then raise Exception.Create('FuncB error');
if not FuncC then raise Exception.Create('FuncC error');


Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39668471
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИнсомниаНо ума не приложу как такое реализовать...
http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/System_Assert@Boolean.html]Assert
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39668476
Инсомниа
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Писать тридцать функций чрез "and"? К тому же они не boolean возвращают, а некие собственные коды.
Код: pascal
1.
2.
3.
4.
5.
6.
Result:=
    (FuncA(...)=GoodResult)
and (FuncB(...)=GoodResult)
and (FuncC(...)=GoodResult)
and ...
;

Да и если функция FuncB() или FuncC() завершилась неуспешно - то остальные двадцать+ уже не надо и пытаться вызывать, бесполезно.

А ещё код ошибки как бы надо бы сообщать:
Код: pascal
1.
2.
3.
4.
5.
6.
FuncResult:=FuncA(...);
if FuncResult<>GoodResult then raise Exception.Create('FuncA error '+FuncResult);
FuncResult:=FuncB(...);
if FuncResult<>GoodResult then raise Exception.Create('FuncB error '+FuncResult);
FuncResult:=FuncC(...);
if FuncResult<>GoodResult then raise Exception.Create('FuncC error '+FuncResult);


Как-то не сильно улучшилось в плане удобности написания/редактирования/чтения... Да и строковые константы вручную писать опять же...
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39668477
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИнсомниаДа и если функция FuncB() или FuncC() завершилась неуспешно - то остальные двадцать+ уже не надо и пытаться вызывать, бесполезно.Они и не вызовутся
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39668479
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Инсомниане boolean возвращают, а некие собственные коды.Я пишу так (для сокетов)
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
procedure RaiseSocketError(AError: Integer);
var
  LExcept: ESocketError;
begin
  LExcept := ESocketError.CreateResFmt(@SOSError, [AError, SysErrorMessage(AError), '']);
  LExcept.ErrorCode := AError;
  raise LExcept;
end;

function SockCheck(ARes: Integer; ASkipNonBlock: Boolean): Integer;
var
  LError: Integer;
begin
  if ARes = SOCKET_ERROR then begin
    LError := WSAGetLastError;
    if not ASkipNonBlock or (LError <> WSAEWOULDBLOCK) then
      RaiseSocketError(LError);
  end;
  Result := ARes;
end;

и использование
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
  Result := SockCheck(Winapi.Winsock2.socket(AF_INET, AType, AProtocol));
  try
    SockCheck(bind(Result, sockaddr(LAddr), SizeOf(LAddr)));
  except
    on E: Exception do begin
      closesocket(Result);
      raise;
    end;
  end;

О том, где возникла ошибка узнаю на основании анализа стека исключения
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39668483
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИнсомниаДа и если функция FuncB() или FuncC() завершилась неуспешно - то остальные двадцать+ уже
не надо и пытаться вызывать, бесполезно.

Так они и не вызовутся: RTFM shortcut boolean evaluation.

ИнсомниаКак-то не сильно улучшилось в плане удобности
написания/редактирования/чтения... Да и
строковые константы вручную писать опять же...

А в чём проблема? Боишься пальцы стереть?
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
Procedure Call(Result: integer; GoodResult: Integer; const Where: String)
begin
   if Result <> GoodResult then
     raise Exception.Create(Where + ' returned ' + Result);
end;

Call(FuncA(1,2,3), 0, 'FuncA');
Call(FuncB(a,b,c), 0, 'FuncB');
Call(FuncC(x,y,z), 0, 'FuncC');


Посмотри как сделано и используется RaiseLastOSError, например.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39668550
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИнсомниаА если у меня "цепочка" не из трёх, а их трёх десятков функций?Если 3 десятка - то 3 десятка строк call( func(..) ).
Если переменное кол-во - то можно подумать о двумерном массиве указателей на функции и структуры их параметров. И в цикле вызывать, пока GoodResult возвращают.
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39668587
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry SibiryakovТак они и не вызовутся: RTFM shortcut boolean evaluation.
Может он отключил, пока руки чесались и теперь переживает. :)
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39668623
Василий 2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Как-то так. Не проверял.
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
type
  TFuncRef = reference to function: Integer;

procedure CallFuncs(const Funcs: array of TFuncRef);
var Func: TFuncRef;
begin
  for Func in Funcs do
    if Func() <> SUCCESS_CODE then
       Break;
end;

var param1, param2, param3...

CallFuncs([
  function (): Integer
  begin
     Result := DoSmth1(param3, param1);
  end,

  function (): Integer
  begin
     Result := DoSmth2(param1, param2);
  end,

  function (): Integer
  begin
     Result := DoSmth1(param1, param3);
  end
]);
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39668637
schi
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Василий 2Как-то так. Не проверял.
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
type
  TFuncRef = reference to function: Integer;

procedure CallFuncs(const Funcs: array of TFuncRef);
var Func: TFuncRef;
begin
  for Func in Funcs do
    if Func() <> SUCCESS_CODE then
       Break;
end;

var param1, param2, param3...

CallFuncs([
  function (): Integer
  begin
     Result := DoSmth1(param3, param1);
  end,

  function (): Integer
  begin
     Result := DoSmth2(param1, param2);
  end,

  function (): Integer
  begin
     Result := DoSmth1(param1, param3);
  end
]);



Вы насоветуете. А потом кому-то этот феерический трындец сопровождать.
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39668966
Василий 2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
schi, это уже за рамками вопроса...
Вообще самый лучший вариант это
автор
Код: pascal
1.
2.
3.
Call(FuncA(1,2,3), 0, 'FuncA');
Call(FuncB(a,b,c), 0, 'FuncB');
Call(FuncC(x,y,z), 0, 'FuncC');
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39670352
AX-Class
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Инсомниа,

Исключения и придуманы, чтоб останавливать ход выполнения.
Если прерывание цепочки вызовов предметно является ошибкой, то лучше писать, как посоветовали.

Если нужно динамическое формирование цепочки, то можно обернуть функции в объекты:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
unit Unit54;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Generics.Collections, Vcl.StdCtrls;

type
  TForm54 = class(TForm)
    Button1: TButton;
    CheckBox1: TCheckBox;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TFuncItem = class
  private
    FStopCode: integer;
  strict protected
    constructor Create(AStopCode: integer);
  public
    function Exec: integer; virtual; abstract;
    procedure HandleStop; virtual; abstract;
  end;

  TFuncA = class(TFuncItem)
  private
    FA: integer;
    FB: integer;
    FC: integer;
  public
    constructor Create(AStopCode, AA, AB, AC: integer); overload;
    function Exec: integer; override;
    procedure HandleStop; override;
  end;

  TFuncB = class(TFuncA)
  public
    function Exec: integer; override;
    procedure HandleStop; override;
  end;

  TFuncC = class(TFuncItem)
  private
    FA: integer;
    FB: integer;
  public
    constructor Create(AStopCode, AA, AB: integer); overload;
    function Exec: integer; override;
    procedure HandleStop; override;
  end;

  TScript = class(TObjectList<TFuncItem>)
  public
    function Exec: TFuncItem;
  end;

function FuncA(a, b, c: integer): integer;

function FuncB(a, b, c: integer): integer;

function FuncC(a, b: integer): integer;

var
  Form54: TForm54;

implementation

{$R *.dfm}

function FuncA(a, b, c: integer): integer;
begin
  Result := 0;
end;

function FuncB(a, b, c: integer): integer;
begin
  Result := 0;
end;

function FuncC(a, b: integer): integer;
begin
  Result := 0;
end;

constructor TFuncA.Create(AStopCode, AA, AB, AC: integer);
begin
  inherited Create(AStopCode);
  FA := AA;
  FB := AB;
  FC := AC;
end;

function TFuncA.Exec: integer;
begin
  Result := FuncA(FA, FB, FC);
end;

procedure TFuncA.HandleStop;
begin
  ShowMessage('TFuncA');
end;

function TFuncB.Exec: integer;
begin
  Result := FuncB(FA, FB, FC);
end;

procedure TFuncB.HandleStop;
begin
  Beep;
end;

function TScript.Exec: TFuncItem;
var
  F: TFuncItem;
  Return: integer;
begin
  for F in Self do
    if F.Exec = F.FStopCode then
      Exit(F);
  Result := nil;
end;

constructor TFuncItem.Create(AStopCode: integer);
begin
  FStopCode := AStopCode;
end;

constructor TFuncC.Create(AStopCode, AA, AB: integer);
begin
  inherited Create(AStopCode);
  FA := AA;
  FB := AB;
end;

function TFuncC.Exec: integer;
begin
  Result := FuncC(FA, FB);
end;

procedure TFuncC.HandleStop;
begin
  ShowMessage('TFuncC');
end;

procedure TForm54.Button1Click(Sender: TObject);
var
  Script: TScript;
  FuncItem: TFuncItem;
begin
  Script := TScript.Create(True);
  try
    Script.Add(TFuncA.Create(-1, 6, 6, 6));
    if CheckBox1.Checked then
      Script.Add(TFuncA.Create(0, 6, 6, 6));
    Script.Add(TFuncB.Create(0, 7, 7, 7));
    Script.Add(TFuncC.Create(0, 1, 1));
    FuncItem := Script.Exec;
    if Assigned(FuncItem) then
      FuncItem.HandleStop;
  finally
    Script.Free;
  end;
end;

end.


С MMX Code Explorer 30 функций обернуть - несколько мин. Виртуальность, одинаковые сообщения, одинаковая сигнатура итд.
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39670369
AX-Class
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Букв можно сократить. Что-то вроде

Script.AddFunc3(CERROR_CODE, FuncA, 6, 6, 6, 'Error Message');
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39670370
AX-Class
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Или, даже

Script.AddFunc<integer, string>(CERROR_CODE, FuncW, 888, 'String Param', 'Error Message');
...
Рейтинг: 0 / 0
Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
    #39670582
Василий 2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Или
Код: pascal
1.
2.
3.
4.
5.
Exec([
  TFuncA.Create(0, 6, 6, 6),
  TFuncB.Create(...),
  ...
])


Тогда и Script не нужен

А если объявить такой класс и функцию
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
TExecutor = class
  class function Exec(Func): TExecutor;
end;

class function TExecutor.Exec(Func): TExecutor;
begin
  DoExec(Func);
  Result := Self;
end;

function Exec(Func): TExecutor;
begin
  Result := TExecutor.Exec(Func);
end;



то можно делать в модной манере цепочкования
Код: pascal
1.
2.
3.
4.
  Exec(TFuncA.Create(0, 6, 6, 6)).
  Exec(TFuncB.Create(...)).
  Exec(TFuncC.Create(...)).
  ...
...
Рейтинг: 0 / 0
16 сообщений из 16, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Как бы вызывать цепочку функций с проверкой каждого шага на возврат кода ошибки?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]