程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Delphi接口編程的兩大陷阱(4)

Delphi接口編程的兩大陷阱(4)

編輯:Delphi

for I := 0 to interList.Count -1 do
Pointer(interList.Items[i]) := nil;

可惜的是,編譯錯誤“[Error] XXXX.pas(XX): Left side cannot be assigned to”。

然後我們試一下array。

interList: Array of I1;

動態數組是不要釋放的。好像很好用,但是編譯器釋放它時還是會對每個元素置為nil的,而且是作為接口,仍然有非法地址訪問錯誤的可能。可以這樣

for i := Low(arr) to High(arr) do
Pointer(arr[i]) := nil;

但是這畢竟是違反編碼習慣的,而且每次使用都要記得作,不記得作也可能不會馬上出錯,所以有可能成為隱患。

最後,就是使用TList。不過TList中是指針,所以Add時必須這樣

procedure XXX.Add(AIntf: I1)
Begin
 InterList.Add(Pointer(AIntf));
End;

由於它本來就保存的是指針,所以釋放時也不需要特殊處理。

好像比較完美,但是還是有一個陷阱,如果你寫了這樣的代碼會怎麼樣呢?

interList.Add(TC2.Create);

或者

Obj2 := TC2.Create;
interList.Add(Obj2);

錯!因為保存的是純粹的指針,所以轉化為接口時,對象引用到接口引用的地址轉換沒有進行(它也不知道如何進行),所以調用接口聲明的方法時就又是一個非法地址訪問錯誤。只能這麼寫:

interList.Add(Pointer(I1(TC2.Create)));

雖然有些麻煩,相比之下這已是最佳方案(我所知的)了。因為你如果你忘記轉會在第一次調用時就出錯,比較容易發現錯誤(相比於使用array)。

所以我建議:

1、使用Tlist來管理接口引用。

2、增加時要把對象轉型成Interface再轉型成Pointer,如果本來就是接口引用的話直接轉為Pointer即可。

3、對於沒有使用Tlist來管理的接口引用。對於接口的引用要用下面的方法手動置為nil:Pointer(IntfRef):= nil;

另外,TInterfacedObject也實現了IInterface的三個方法。所以從它繼承也可以省去自己實現這三個方法的麻煩。但是它的_Release是這樣實現的:

function TInterfacedObject._Release: Integer;
begin
 Result := InterlockedDecrement(FRefCount);
 if Result = 0 then
  Destroy;
end;

我們前邊說過,接口引用的置nil會調用接口的_Release,所以有可能會把對象給釋放掉,我當時可是被它嚇了一跳,多虧我沒用過它。也就是這樣實現下比從TComponent繼承帶來更大的麻煩。除非特殊用途,不建議使用。

上面對接口的所有討論,只限於普通使用的語言級的接口,沒有討論Com+接口。Delphi的這些詭異的接口的實現,和它是從Com+接口發展而來是有很大關系的,也就是由於背負了過重的歷史包袱而作出的妥協的結果。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved