Je vedro tak to trošku okořeníme. Mějme následující kód a odhadněte bez krokování, kde a zda vůbec program spadne. Je to umělá ukázka reálné situace, kterou jsem ale trošku zamaskoval ať je to zábavnější.
Možnosti k přemýšlení: spadne to protože volám metodu na nil objektu, spadne to protože TButton v console, spadne to protože TButton má taky Click, spadne to protože se snažím vypsat Caption a to je řetezec, spadne to protože se snažím nastavit Caption a to teprve nemůže projít, spadne to protože mám lokální proměnnou v metodě u nil objektu, spadne to protože přiřazují do lokální proměnné, spadne to protože čtu lokální proměnnou nil objektu, spadne to náhodou a jen někdy.
Nebo to v klidu projde vše. Jako je to trošku vyšší level, ale zkuste.
program TestAV;
{$APPTYPE CONSOLE}
{$R *.res}
uses
WinApi.Windows, System.SysUtils, System.Classes, WinApi.Messages, Vcl.StdCtrls;
type
TTestButton = class(TButton)
public
procedure Click;
end;
procedure TTestButton.Click;
var
x: Integer;
begin
writeln('button.Click'); // Line A
writeln(Caption); // Line B
Caption := 'Button 23'; // Line C
x := ImageIndex; // Line D
writeln(IntToStr(x)); // Line E
end;
var
t: TTestButton;
begin
try
t:=nil;
t.Click; // Line F
t.Free; // line G
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.
Volání metody na nil objektu projde v případě, že se nedotknete proměnných objektu. Interně to funguje tak, že metoda objektu je kus společného kódu, který v prvním parametru (skrytém) dostane adresu na data objektu. V našem případě je to nil, a do té doby, než na data šáhneme je to v klidu.
Metoda Free má test, zda není volaná na nil objektu. Tím máme vyřešené A, F, G.
Zbývá B, C, D, E.
Lokální proměnná je v pohodě, pokud do ní nepřiřadíme něco z objektu. Takže E je taky OK. Proč to nespadne na B a C? Tady je to ode mne trošku zákeřné, protože Caption je property, která má čtecí a zápisovou metodu a ty mají z důvodu Win32 API a posílání zpráv pro jistotu test na nil, takže projdou a můžete to vzít jako zákeřnost pro ilustraci.
A zbývá nám D, což je sice taky property, ale pro čtení nemá metodu a čte přímo data objektu (pro rychlost) a zde konečně narazí kosa na kámen a výsledkem je AV. Prostě při jakémkoliv kontaktu s daty objektu v našem případě narazíme.
Platí to obecně, TButton je jen vhodný kandidát.
Datum: 2024-06-27 15:02:00 Tagy: praxe