2011-12-15 88 views
8

this question about interface fields in records後,我認爲以下將工作(注意斷言):功能與接口的現場返回記錄

type 
    TRec <T> = record 
    Intf : IInterface; 
    end; 

    TTestClass = class 
    public 
    function ReturnRec : TRec <Integer>; 
    end; 

    // Implementation 
    function TTestClass.ReturnRec : TRec <Integer>; 
    begin 
    Assert (Result.Intf = nil); // Interface field in record should be initialized! 
    Result.Intf := TInterfacedObject.Create; 
    end; 

我用下面的代碼測試此:

for I := 1 to 1000 do 
    Rec := Test.ReturnRec; 

和斷言失敗!

哪裏是我的錯嗎?什麼假設是錯誤的?

+0

是否斷言失敗環路的第一或第二次運行? – Johan 2011-12-15 11:52:56

+0

@Smasher FWIW,這就是我在想,如果我寫我的不正確的答案的:http://stackoverflow.com/questions/5102843/delphi-function-result-not-emptied-during-for-loop – 2011-12-15 13:14:05

回答

12

功能

function ReturnRec: TRec<Integer>; 

在語義上等於程序

procedure ReturnRec(var Result: TRec<Integer>); 

[我敢肯定,有人從Embarcadero公司,可能是巴里·凱利和艾倫·鮑爾說這個地方,但我不能找到此刻的參考。]

在第二種情況下,編譯器假定該記錄將被初始化(如果需要)它被傳遞給ReturnRec和前不會爲ReturnRec中的rec創建任何初始化代碼。我假設第一個例子中編譯器內部的代碼路徑相同,這就是爲什麼Result沒有被初始化。

總之,解決方法很簡單:

function TTestClass.ReturnRec : TRec <Integer>; 
begin 
    Result.Intf := TInterfacedObject.Create; 
end; 

只是假設,編譯器知道它在做什麼,並指定界面,一切都將工作得很好。

編輯

你有這個問題從 'for' 循環發生。您的代碼

for I := 1 to 1000 do 
    Rec := Test.ReturnRec; 

被編譯成這樣的:

var 
    result: TRec<Integer>; 

Initialize(result); 
for I := 1 to 1000 do begin 
    Test.ReturnRec(result); 
    rec := result; 
end; 

這就是爲什麼你在各地重複使用相同的記錄,這就是爲什麼Result.Intf是初始化只是第一次。

EDIT2

您可以通過移動t.ReturnRec從循環調用到一個單獨的方法欺騙編譯器。

procedure GetRec(t: TTest; var rec: TRec); 
begin 
    rec := t.ReturnRec; 
end; 

for i := 1 to 1000 do 
    GetRec(t, rec); 

現在,隱藏的結果變量駐留在GetRec過程中,並在每次調用GetRec時進行初始化。