Dies ist ein Compilerfehler. Hier ist meine vereinfachte Wiedergabe:
{$APPTYPE CONSOLE}
type
TProc = reference to procedure;
TOnObject = procedure of object;
procedure Invoke(Proc: TProc);
begin
if Assigned(Proc) then
Proc();
end;
procedure CallInvokeOnObject(OnObject: TOnObject);
begin
Invoke(OnObject);
end;
begin
Invoke(nil); // succeeds
CallInvokeOnObject(nil); // results in AV
end.
Sie könnten sich fragen, warum ich vereinfacht. Ihr Code war eine hervorragende Reproduktion des Problems. Ich wollte es jedoch so einfach wie möglich machen, damit ich wirklich sicher sein konnte, dass das Problem das war, was ich glaube. Also habe ich die Generika und die Klassen entfernt.
Jetzt ist der Test mit Assigned
korrekt. Sie haben zu Recht erwartet, dass es sich so verhält, wie Sie es beabsichtigen. Das Problem besteht darin, dass wenn der Compiler Code generiert, um Invoke
von CallInvokeOnObject
aufzurufen, die Methode des Objekts in einer Referenzprozedurschnittstelle umbrechen muss. Um dies richtig durchzuführen, müsste geprüft werden, ob die Objektmethode zugewiesen ist oder nicht. Wenn nicht, sollte keine Wrapper-Schnittstelle erstellt werden und Invoke
sollte nil
übergeben werden.
Der Compiler schlägt das nicht. Sie umschließt die Objektmethode in einer Referenzprozedurschnittstelle bedingungslos. Sie können dies in dem Code sehen, der für CallInvokeOnObject
ausgegeben wird.
Project1.dpr.16: begin // this is the beginning of CallInvokeOnObject
004064D8 55 push ebp
004064D9 8BEC mov ebp,esp
004064DB 6A00 push $00
004064DD 53 push ebx
004064DE 33C0 xor eax,eax
004064E0 55 push ebp
004064E1 683B654000 push $0040653b
004064E6 64FF30 push dword ptr fs:[eax]
004064E9 648920 mov fs:[eax],esp
004064EC B201 mov dl,$01
004064EE A1F4634000 mov eax,[$004063f4]
004064F3 E8DCDAFFFF call TObject.Create
004064F8 8BD8 mov ebx,eax
004064FA 8D45FC lea eax,[ebp-$04]
004064FD 8BD3 mov edx,ebx
004064FF 85D2 test edx,edx
00406501 7403 jz $00406506
00406503 83EAF8 sub edx,-$08
00406506 E881F2FFFF call @IntfCopy
0040650B 8B4508 mov eax,[ebp+$08]
0040650E 894310 mov [ebx+$10],eax
00406511 8B450C mov eax,[ebp+$0c]
00406514 894314 mov [ebx+$14],eax
Project18.dpr.17: Invoke(OnObject);
00406517 8BC3 mov eax,ebx
00406519 85C0 test eax,eax
0040651B 7403 jz $00406520
0040651D 83E8E8 sub eax,-$18
00406520 E8DFFDFFFF call Invoke
das zu TObject.Create
nennen ist, was die Methode des Objektes in einem Referenzverfahren Schnittstelle einwickelt. Beachten Sie, dass die Schnittstelle bedingungslos erstellt und dann an Invoke
übergeben wird.
Es gibt keine Möglichkeit für Sie, dies von innen zu umgehen Invoke
. Wenn der Code dort ankommt, ist es zu spät. Sie können nicht feststellen, dass die Methode nicht zugewiesen ist. Dies sollte Embarcadero als Fehler gemeldet werden.
Ihre einzige praktikable Problemumgehung ist, eine zusätzliche zugewiesene Überprüfung in CallInvokeOnObject
hinzuzufügen.
gemeldet als [RSP-10204] (https://quality.embarcadero.com/browse/RSP-10204) –
@Martin Sie könnten die Version sinnvollerweise auf XE7 Update 1 mit der Versionsnummer 21.0.17707.5020 ändern. Das ist das Neueste, und wo ich meine Tests gemacht habe. –