2011-12-16 3 views
4

Последующий вопрос до this question: (обратите внимание, что это не дубликат, я прошу об альтернативах здесь).Реализация списка с записями

Есть ли способ, чтобы сделать следующую работу:

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; 

Благодарим за помощь!

+0

Rob объяснил в своем последнем вопросе, что 'Initialize' была ошибкой в ​​ответе gabr. Так что нет, вы не должны этого использовать. –

+0

Вот что я написал ... вопрос в том, есть ли другие способы сделать эту работу, или просто невозможно создать типы значений, содержащие объекты. – jpfollenius

+0

Вы собираетесь против правил в Delphi здесь. Вы можете получить определенное расстояние по «дороге» при этом, но вы обнаружите, что для вашего метода типа RECORD существуют большие затраты. –

ответ

2

Это должно работать нормально, если я вас правильно понял:

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; 

Лично, так как вы вносите интерфейс в миксе, я думаю, что я был бы склонен идти весь путь и использовать интерфейсы исключительно. Или используйте стандартные классы и соглашайтесь с необходимостью управления временем/try/finally.

+0

Спасибо, я пропустил эту информацию! Не очень интуитивно. Я могу пойти на решение интерфейса. К сожалению, я потеряю возможность использовать перегрузку оператора :( – jpfollenius

+0

Я должен сказать, что я никогда не слышал об этой функции «Инициализация» до вашего вопроса вчера! –

+0

Спасибо за ввод! Это первый раз, когда я нахожу язык действительно ограничивает.Либо я вынуждаю всех вызывающих абонентов запоминать вызов 'Finalize' при его использовании таким образом, либо я должен отказаться от перегрузки оператора и общих методов в списке. По-прежнему возможны некоторые улучшения, чтобы сделать язык более универсальным, я думаю. – jpfollenius

Смежные вопросы