2013-05-30 10 views
2

我正在嘗試使用線程進行Web服務調用。出於這個原因,我定義了一個簡單的對象並從一個線程調用它的方法。在Delphi中,我可以使用一個被破壞的對象而不會出錯!可能嗎?

但我意識到,銷燬該對象後,我仍然可以使用它的方法沒有任何錯誤,它會返回正確的答案。怎麼可能?你有什麼評論嗎?

// TThreadMethod is defined in Classes.pas 

TThreadMethod = procedure of object; 


********************* 
     Interface 
********************* 

TMyObject = class(TObject) 
    procedure DoSomething; 
end; 

TMyThread = class(TThread) 
private 
    FMethod : TThreadMethod; 
protected 
    procedure Execute; override; 
public 
    constructor Create(aMethod: TThreadMethod); 
end; 

********************* 
    Implementation 
********************* 

// I called the thread and destroyed the object immediately. 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    aObject : TMyObject; 
begin 
    aObject := TMyObject.Create; 
    TMyThread.Create(aObject.DoSomething); 
    FreeAndNil(aObject); // Object itself was destroyed here. 
end; 

constructor TMyThread.Create(aMethod: TThreadMethod); 
begin 
    inherited Create(True); 
    FreeOnTerminate := True; 
    FMethod := aMethod; 
    Resume; 
end; 

procedure TMyThread.Execute; 
begin 
    Sleep(10000); // wait 10 sec. before calling the method 
    // The object was already destroyed but it doesn't produce any error! 
    FMethod; // It calls the web service method and returns correct result. But how???  
end; 

procedure TMyObject.DoSomething; 
begin 
    // Call a web service method and show the result on the form. 
end; 
+1

在一定程度上,是的,這是可能。但當然不推薦。對象的方法可以工作,只要沒有字段,如字符串,整數或任何需要內存分配的其他字段。如果在這個函數中有'FSomeString:='Some Value';'它會失敗,假設這個字符串在對象中。但它可以處理對象外的數據。 –

+0

[爲什麼在調用.Free後爲Delphi對象賦值?](http://stackoverflow.com/questions/235033/why-are-delphi-objects-assigned-even-after-calling-free) –

+0

否這與這個問題不同。在那個問題中,這個問題與指針的零分配有關。在我的情況下,我摧毀了對象本身,但它的方法仍然有效。他們完全不同。 –

回答

7

的方法是不依賴於對象,但對類...

type 
TMyObject = class(TObject) 
published 
    procedure DoSomething; 
end; 
TSomeProcedure=Procedure of object; 

    TForm1 = class(TForm) 
    ..... 
    end; 

var 
    Form1: TForm1; 

implementation  
{$R *.dfm}  
procedure TForm1.Button2Click(Sender: TObject); 
var 
p:TSomeProcedure; 
M:TMethod; 
begin 
m.Code := TMyObject.MethodAddress('DoSomething'); 
m.Data := nil; 
p := TSomeProcedure(m); 
p; 
end; 

procedure TMyObject.DoSomething; 
begin 
    Showmessage('Hallo'); 
end; 

EDIT一個附加的例子將是

type 
TMyObject = class(TObject) 
published 
    procedure DoSomething; 
end; 
procedure TMyObject.DoSomething; 
begin 
    Showmessage('Hallo'); 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
o1,o2:TMyObject; 
begin 
o1:=TMyObject.Create; 
o2:=TMyObject.Create; 
Memo1.Lines.Add(IntToHex(Integer(TMyObject.MethodAddress('DoSomething')),4)); 
Memo1.Lines.Add(IntToHex(Integer(o1.MethodAddress('DoSomething')),4)); 
Memo1.Lines.Add(IntToHex(Integer(o2.MethodAddress('DoSomething')),4)); 
o1.Free; 
o2.Free; 
end; 
+0

這非常有趣!我不知道。感謝這些例子。 –

+0

@JackHouston注意到這些方法是靜態的。虛擬/動態/消息方法不能用這種奇特的方式。如果你真的需要這樣的事情 - 閱讀「類方法」。 –

+0

@ Arioch'The:在被銷燬的實例上使用任何類型的非類方法確實會觸發任何異常。如果內存尚未被覆蓋,或者這些方法不使用任何實例變量,則執行可能成功,並且當它啓動失敗時,您將進入一個良好的調試會話。 「它曾經工作,爲什麼它突然拋出一個異常」,或者甚至:「它在這裏工作,但在另一個線程失敗,或者三次循環迭代失敗。」 –

相關問題