Проблема в исходном коде заключалась в том, что вы добавляли указатель IFile
в список, но когда вы позже читали значение из списка, вы назначали указатель непосредственно другому * 1004. * переменная. Таким образом, вы имели значение PIFile
, сохраненное в переменной IFile
. Как правило, Delphi позволяет назначать нетипизированный тип Pointer
любому типу указателя, включая интерфейсы.
Чтобы исправить исходный код, вам нужно написать второй вид примерно так:
var
p: Pointer;
for i := 0 to Pred(Files.Count) do begin
p := Files.Files[i];
if not Assigned(p) then
continue;
f := IFile(p^);
if not Assigned(f) then
continue;
Memo1.Lines.Add(f.Filename);
end;
Вы были правы, чтобы позвонить f._AddRef
в своем первом цикле. Когда возвращается IFiles.Add
, счетчик ссылок на результат равен 1
, поскольку значение, хранящееся в цикле, является указателем, а не фактической ссылкой. Вам нужно увеличить счетчик ссылок, потому что f
будет повторно использоваться для других значений. Поскольку подсчитываемая вручную ссылка хранится в списке FFiles
, было бы лучше вызвать _AddRef
внутри IFiles.Add
, а не ждать, пока она не вернется.
Когда вы очищаете список или удаляете элементы из списка, вам нужно будет вызвать _Release
для всех ссылок интерфейса.
Но Ответ Тоби дает лучшую идею: используйте TInterfaceList
для хранения списка интерфейсов. TList
просто не подходит для этой задачи.
Последний совет: префикс «I» в именах используется для обозначения интерфейс типов. Интерфейсы не имеют собственных реализаций методов. Вы показали реализацию IFiles.Add
, поэтому IFiles
явно не тип интерфейса. Вместо этого оно должно быть названо TFiles
или, может быть, TFileList
.