У меня есть простой класс, который имеет следующую реализацию интерфейса.
Примечание : TPolyBase
является абстрактным классом, а TPolyResult
является array of double
; не важно видеть их код, это не имеет значения здесь.
//INTERFACE
type
TPolynomialList = class
strict private
FPolynomialList: TObjectList<TPolyBase>;
FResult: TList<TPolyResult>;
FCanGet: boolean;
function GetResult: TList<TPolyResult>;
procedure DoSolve;
public
constructor Create(PolynomialList: TObjectList<TPolyBase>);
destructor Destroy; override;
procedure SolvePolynomials(CompletionHandler: TProc);
property Solutions: TList<TPolyResult> read GetResult;
end;
//IMPLEMENTATION
constructor TPolynomialList.Create(PolynomialList: TObjectList<TPolyBase>);
begin
FPolynomialList := PolynomialList;
FResult := TList<TPolyResult>.Create;
FCanGet := false;
end;
destructor TPolynomialList.Destroy;
begin
FResult.Free;
inherited;
end;
procedure TPolynomialList.DoSolve;
var
i: integer;
begin
for i := 0 to FPolynomialList.Count - 1 do
FResult.Add(FPolynomialList[i].GetSolutions);
FCanGet := true;
end;
function TPolynomialList.GetResult: TList<TPolyResult>;
begin
if FCanGet = false then
raise TEquationError.Create('You must solve the equation first!');
Result := FResult;
end;
procedure TPolynomialList.SolvePolynomials(CompletionHandler: TProc);
begin
TTask.Run(procedure
var
ex: TObject;
begin
try
DoSolve;
TThread.Synchronize(nil, procedure
begin
CompletionHandler;
end);
except
on E: Exception do
begin
ex := AcquireExceptionObject;
TThread.Synchronize(nil, procedure
begin
Writeln( (ex as Exception).Message );
end);
end;
end;
end);
end;
Этот класс принимает список объектов в качестве входных данных и имеет внутреннее важное поле с именем FResult
, которое предоставляет результаты пользователю. Доступ к нему можно получить из геттера, только если метод SolvePolynomials завершил свою работу.
Проблема в SolvePolynomials
. Код, который я показал, использует задачу, потому что размер списка объектов может быть очень большим, и я не хочу замораживать пользовательский интерфейс. Почему я всегда получаю нарушение прав доступа в коде задачи?
Обратите внимание, что следующий код работает нормально, но это не то, что я хочу, потому что, если я введу 15000, программа остановится на несколько секунд.
procedure TPolynomialList.SolvePolynomials(CompletionHandler: TProc);
begin
DoSolve;
CompletionHandler;
end;
Может быть проблема с переменной FPolynomialList
? Если вы посмотрите на мой класс, единственное, что «взято извне» - это TObjectList<TPolyBase>
, потому что в конструкторе я просто использую ссылку (я хотел бы избежать копирования в порядке 15k элементов). Все остальные переменные ни с кем не используются.
Я видел во многих книгах, которые я читал, например, «Delphi High Performance», что хорошо иметь задачу, которая вызывает внутренний «медленный» метод, но в этом случае могут быть ссылки, которые что-то портят. Любая идея?
Это код, который я использую в качестве теста:
var
a: TObjectList<TPolyBase>;
i, j: integer;
f: TPolynomialList;
s: string;
function GetRandom: integer;
begin
Result := (Random(10) + 1);
end;
begin
a := TObjectList<TPolyBase>.Create(true);
try
for i := 0 to 15000 do
begin
a.Add({*Descendant of TPolyBase*})
end;
f := TPolynomialList.Create(a);
try
f.SolvePolynomials(procedure
var
i, j: integer;
begin
for i := 0 to f.Solutions.Count - 1 do
begin
for j := Low(f.Solutions[i]) to High(f.Solutions[i]) do
Writeln({output the results...})
end;
end);
finally
f.Free;
end;
finally
a.Free;
end;
end.