При разработке большого проекта столкнулся со следующей проблемой, вот тестовый проект отображающий её: | Код | program Test;
{$APPTYPE CONSOLE}
uses SysUtils;
type TError = class private function Add(FromV, ToV: Integer): Integer; function Check(Row: Integer; Val: Byte): Boolean; function Operation(Index: Integer; Func: TFunc<Integer,Integer>): Integer; public function Run(Count: Integer): Integer; end;
function TError.Add(FromV, ToV: Integer): Integer; var i: Integer; res: Integer; func: TFunc<Integer,Integer>; begin res := 0; func := function(data: Integer): Integer begin if Check(i, 127) then Result := data; end;
for i := FromV to ToV do res := Operation(i, func);
Result := res; end;
function TError.Check(Row: Integer; Val: Byte): Boolean; begin Result := True; end;
function TError.Operation(Index: Integer; Func: TFunc<Integer, Integer>): Integer; begin if Assigned(Func) then Result := Func(Index); end;
function TError.Run(Count: Integer): Integer; begin Result := Add(0, Count); end;
begin try with TError.Create do begin WriteLn('Count: 32766; Run: ', Run(32766)); WriteLn('Count: 32768; Run: ', Run(32768)); end; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; ReadLn; end.
|
При запуске получаем: | Код | Count: 32766; Run: 32766 Count: 32768; Run: 0
|
То есть, во втором случае цикл не выполняется ни разу. А вот код, который создаёт компилятор для цикла: | Код | 0040F8D0 FF400C inc dword ptr [eax+$0c] Test.dpr.32: for i := FromV to ToV do 0040F8D3 8B45E0 mov eax,[ebp-$20] 0040F8D6 8B400C mov eax,[eax+$0c] 0040F8D9 663B45E6 cmp [U]ax[/U],[ebp-$1a] 0040F8DD 7ED7 jle $0040f8b6 {переход на тело}
|
Тут видно, что сравнение идёт с 16-ти битным целым, хотя должно быть 32 бита. Запостил отчёт на QualityCentral: http://qc.embarcadero.com/wc/qcmain.aspx?d=99909Проблему можно обойти выносом анонимной функции в метод, вот так: | Код | TError = class private _i: integer; function Add(FromV, ToV: Integer): Integer; function Check(Row: Integer; Val: Byte): Boolean; function Operation(Index: Integer; Func: TFunc<Integer,Integer>): Integer; function AFunc(AData: Integer): Integer; public function Run(Count: Integer): Integer; end;
function TError.Add(FromV, ToV: Integer): Integer; var i: Integer; res: Integer; func: TFunc<Integer,Integer>; begin res := 0;
for i := FromV to ToV do res := Operation(i, AFunc);
Result := res; end;
function TError.AFunc(AData: Integer): Integer; begin if Check(_i, 127) then Result := AData; end;
function TError.Operation(Index: Integer; Func: TFunc<Integer, Integer>): Integer; begin _i := Index; if Assigned(Func) then Result := Func(Index); end;
|
|