Изпълнение на списък със записи

Допълнителен въпрос към този въпрос: (имайте предвид, че това не е дубликат , питам за алтернативи тук).

Има ли някакъв начин следното да работи:

type
  List <T> = record
  private
    FList  : TList <T>;
    FGuard : IInterface,
    procedure CheckCreated;
  public
    procedure Add(const Value : T);
  end;

procedure List <T>.CheckCreated;
begin
if (FGuard = nil) then
  begin
  FList := TList <T>.Create;
  FGuard := TGuard.Create (FList);    // guard calls free on list in destructor
  end;
end;

procedure List <T>.Add (const Value : T);
begin
CheckCreated;
FList.Add (Value);
end;

В идеалния случай искам да го използвам така:

function ReturnHandles : List <THandle>;
begin
Result.Add (2);
Result.Add (3);
end;

Както е обяснено в отговорите на свързания въпрос, това не работи (което наистина е жалко). Няма да създава нов списък при всяко повикване.

За съжаление и това не работи:

function ReturnHandles : List <THandle>;
begin
Initialize (Result);
Result.Add (2);
Result.Add (3);
end;

Изтича интерфейсите на охраната и всички списъци, защото Initialize просто презаписва препратката към интерфейса, без да намалява броя на препратките.

Има ли някакъв начин това да работи? Или бихте предложили да направите това интерфейс вместо запис и просто да живеете с строителната линия?

function ReturnHandles : List <THandle>;
begin
Result := List <T>.Create;
Result.Add (2);
Result.Add (3);   
end;

Благодаря за вашата помощ!


person jpfollenius    schedule 16.12.2011    source източник
comment
Роб обясни в последния ви въпрос, че Initialize е грешка в отговора на gabr. Така че не, не трябва да използвате това.   -  person David Heffernan    schedule 16.12.2011
comment
Това е, което написах... въпросът е дали има някакви други начини това да работи или просто не е възможно да се създадат типове стойности, които съдържат обекти   -  person jpfollenius    schedule 16.12.2011
comment
Вие нарушавате правилата в Delphi тук. Може да постигнете известно разстояние по пътя, като правите нещата по този начин, но ще откриете, че има големи разходи за вашия подход тип RECORD.   -  person Warren P    schedule 17.12.2011
comment
@WarrenP можеш ли да изясниш какви са големите разходи според теб?   -  person jpfollenius    schedule 19.12.2011
comment
Например възнамерявате ли да разрешите дълбоки копия на тези списъци, базирани на записи?   -  person Warren P    schedule 19.12.2011
comment
@WarrenP Да, List.Copy. Неявните копия се държат по същия начин като препратките (препратката към вътрешния списък се копира), което е доста хубаво.   -  person jpfollenius    schedule 20.12.2011


Отговори (1)


Това трябва да работи добре, ако ви разбирам правилно:

function ReturnHandles : List <THandle>;
begin
  Finalize(Result);
  Result.Add (2);
  Result.Add (3);
end;

Извикването Finalize ще гарантира, че всички управлявани типове са зададени на nil, което според мен е вашето намерение.

Този въпрос е много тясно свързан с предишния ви въпрос и мисля, че можете да използвате out параметри, за да опростите кода. Резултатът от функцията имплицитно е var параметър, но ако сте използвали явен out параметър, той ще инициализира управляваните типове, както желаете.

procedure InitializeHandles(out Handles : List <THandle>);
begin
  Handles.Add (2);
  Handles.Add (3);
end;

Лично, тъй като въвеждате интерфейс в микса, мисля, че бих бил склонен да отида докрай и да използвам изключително интерфейси. Или използвайте стандартни класове и приемете необходимостта от доживотно управление на опита/накрая.

person David Heffernan    schedule 16.12.2011
comment
Благодаря, пропуснах тази информация! Не много интуитивен обаче. Може да се насоча към интерфейсното решение. За съжаление тогава ще загубя възможността да използвам претоварване на оператора :( - person jpfollenius; 16.12.2011
comment
Трябва да кажа, че никога не бях чувал за тази функция Initialize до въпроса ви вчера! - person David Heffernan; 16.12.2011
comment
Благодаря за приноса! Това е първият път, когато намирам езика за наистина ограничаващ. Или трябва да принудя всички викащи да запомнят да извикат Finalize, когато го използвам по този начин, или трябва да се откажа от претоварването на оператора и общите методи в списъка. Все пак са възможни някои подобрения, които да направят езика по-гъвкав, предполагам. - person jpfollenius; 16.12.2011
comment
Опитвали ли сте да използвате параметър out вместо функция? out има различна семантика от параметър var (какъв е резултатът от функцията) и трябва да прави това, което искате. - person David Heffernan; 16.12.2011
comment
Параметърът Out работи, но елиминира част от предимството на цялата идея: възможността да напишете по-четливия Handles := GetHandles вместо GetHandles(Handles). - person jpfollenius; 16.12.2011
comment
@Smasher Да, мисля, че тук няма идеално решение, което да постига всичките ви цели - person David Heffernan; 16.12.2011