Le code
with TClipper.Create do
try
AddPolygon(subject, ptSubject);
AddPolygon(clip, ptClip);
Execute(ctIntersection, solution);
finally
free;
end
est un raccourci pour
with TClipper.Create do
begin
try
AddPolygon(subject, ptSubject);
AddPolygon(clip, ptClip);
Execute(ctIntersection, solution);
finally
free;
end;
end;
TClipper.Create
crée un objet de type TClipper
, et renvoie celle-ci et la déclaration with
, qui fonctionne comme dans la plupart des langues, vous permet d'accéder les méthodes et les propriétés de cet objet TClipper sans utiliser la syntaxe NameOfObject.MethodOrProperty
.
(Un exemple plus simple:
MyPoint.X := 0;
MyPoint.Y := 0;
MyPoint.Z := 0;
MyPoint.IsSet := true;
peut être simplifié à
with MyPoint do
begin
X := 0;
Y := 0;
Z := 0;
IsSet := true;
end;
)
Mais dans votre cas, vous ne devez déclarer un objet TClipper comme une variable, parce que vous le créez et pouvez accéder à ses méthodes et propriétés au moyen de la construction with
.
donc votre code est presque equivelant à
var
Clipper: TClipper;
Clipper := TClipper.Create;
Clipper.AddPolygon(subject, ptSubject);
Clipper.AddPolygon(clip, ptClip);
Clipper.Execute(ctIntersection, solution);
Clipper.Free;
La première ligne, Clipper := TClipper.Create
, crée un objet TClipper
.Les trois lignes suivantes fonctionnent avec cet objet, puis Clipper.Free
détruit l'objet, libérant de la RAM et éventuellement des ressources de temps et de système d'exploitation de l'UC, utilisées par l'objet TClipper
.
Mais le code ci-dessus n'est pas bon, parce que si un occurrs d'erreur (une exception est créée) dans AddPolygon
ou Execute
, le Clipper.Free
ne sera jamais appelé, et si vous avez une fuite de mémoire. Pour éviter cela, Delphi utilise la try...finally...end
construction:
Clipper := TClipper.Create;
try
Clipper.AddPolygon(subject, ptSubject);
Clipper.AddPolygon(clip, ptClip);
Clipper.Execute(ctIntersection, solution);
finally
Clipper.Free;
end;
Le code entre finally
et end
est garanti de fonctionner, même si une exception est créée, et même si vous appelez Exit
, entre try
et finally
. Ce que veut dire Mason, c'est que parfois la construction with
peut être une peinture dans le cerveau, à cause de conflits d'identifiants. Par exemple, considérons
MyObject.Caption := 'My test';
Si vous écrivez ceci à l'intérieur d'une construction with
, à savoir si vous écrivez
with MyObect do
begin
// A lot of code
Caption := 'My test';
// A lot of code
end;
alors vous pourriez devenir confus. En effet, le plus souvent Caption :=
modifie la légende du formulaire en cours, mais maintenant, en raison de l'instruction with
, il va changer la légende de MyObject à la place.
Pire encore, si
MyObject.Title := 'My test';
et MyObject n'a pas de propriété Caption
, et vous oubliez cela (et je pense que la propriété est appelée Caption
), puis
MyObject.Caption := 'My test';
ne sera même pas compiler, alors
with MyObect do
begin
// A lot of code
Caption := 'My test';
// A lot of code
end;
compilera très bien, mais il ne fera pas ce que tu attends
En outre, construit comme
with MyObj1, MyObj2, ..., MyObjN do
ou imbriquées with
déclarations comme dans
with MyConverter do
with MyOptionsDialog do
with MyConverterExtension do
..
peut produire beaucoup de conflits.
la défense de la Déclaration With
Je remarque qu'il ya presque un consensus (au moins dans ce fil) que la déclaration with
est plus mal que de bien. Bien que je sois conscient de la confusion potentielle et que j'y suis tombé plusieurs fois, je ne peux pas être d'accord. Une utilisation minutieuse de l'instruction with
peut rendre le code beaucoup plus joli. Et cela diminue le risque de confusion dû à "barfcode".
Par exemple:
Comparez
var
verdata: TVerInfo;
verdata := GetFileVerNumbers(FileName);
result := IntToStr(verdata.vMajor) + '.' + IntToStr(verdata.vMinor) + '.' + IntToStr(verdata.vRelease) + '.' + IntToStr(verdata.vBuild);
avec
with GetFileVerNumbers(FileName) do
result := IntToStr(vMajor) + '.' + IntToStr(vMinor) + '.' + IntToStr(vRelease) + '.' + IntToStr(vBuild);
Il n'y a absolument aucun risque de confusion, et non seulement nous sauvons une variable temporaray dans le dernier cas - il est également beaucoup plus lisible.
Ou qu'en est-ce très, très, code standard:
with TAboutDlg.Create(self) do
try
ShowModal;
finally
Free;
end;
exactement où est le risque de confusion? De mon propre code, je pourrais donner des centaines d'autres exemples d'instructions, tout en simplifiant le code.
En outre, comme indiqué ci-dessus, il n'y a aucun risque d'utiliser with
, tant que vous savez ce que vous faites. Mais que faire si vous souhaitez utiliser une instruction with
avec le MyObject
dans l'exemple ci-dessus: puis, à l'intérieur de l'instruction with
, Caption
est égal à MyObject.Caption
. Comment changer la légende du formulaire, alors? Simple!
with MyObject do
begin
Caption := 'This is the caption of MyObject.';
Self.Caption := 'This is the caption of Form1 (say).';
end;
Un autre endroit où avec peut être utile est lorsque vous travaillez avec une propriété ou d'un résultat fonction qui prend un montant non négligeable de temps à exécuter.
Pour travailler avec l'exemple ci-dessus TClipper, supposons que vous avez une liste de TClipper objets avec une méthode lente qui retourne la tondeuse pour un tabsheet particulier.
Idéalement, vous ne devez appeler ce getter qu'une seule fois. Vous pouvez donc utiliser une variable locale explicite ou implicite en utilisant avec.
var
Clipper : TClipper;
begin
Clipper := ClipList.GetClipperForTab(TabSheet);
Clipper.AddPolygon(subject, ptSubject);
Clipper.AddPolygon(clip, ptClip);
Clipper.Execute(ctIntersection, solution);
end;
OU
begin
with ClipList.GetClipperForTab(TabSheet)do
begin
AddPolygon(subject, ptSubject);
AddPolygon(clip, ptClip);
Execute(ctIntersection, solution);
end;
end;
Dans un cas comme celui-ci, ou l'autre méthode ferait, mais dans certaines circonstances, généralement dans un complexe conditionals avec peut être plus clair.
var
Clipper : TClipper;
begin
Clipper := ClipList.GetClipperForTab(TabSheet);
if (Clipper.X = 0) and (Clipper.Height = 0) and .... then
Clipper.AddPolygon(subject, ptSubject);
end;
OU
begin
with ClipList.GetClipperForTab(TabSheet) do
if (X = 0) and (Height = 0) and .... then
AddPolygon(subject, ptSubject);
end;
En fin de compte est est question de goût personnel. Je vais généralement utiliser un avec avec une portée très étroite, et ne jamais les imbriquer. Utilisé de cette façon, ils sont un outil utile pour réduire code à barres.
Méfiez-vous des déclarations peut conduire à des erreurs très trompeuses. Dites que le code est à l'intérieur d'un autre objet tel que TForm1. Quelle méthode est appelée TClipper.Free ou TForm1.Free. Le avec prend la priorité sur la portée, mais il est commun pour les développeurs de manquer cela et d'obtenir des bogues involontaires. –
@Robert Love: Mais la construction montrée ci-dessus est très standard. –
@Andreas Je ne suis pas d'accord, je le vois de temps en temps mais la plupart du code que je regarde n'utilise jamais cette construction, en raison des problèmes qui peuvent surgir de son utilisation. –