可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
is there a way to reference an object instance that is created using the "with" statement?
Example:
with TAnObject.Create do
begin
DoSomething(instance);
end;
Where DoSomething would use the instance reference as if you were passing an instance from a variable declared reference to the object created.
Example:
AnObject := TAnObject.Create;
Thanks.
回答1:
Well, you can use such approach:
// implement:
type
TSimpleMethod = procedure of object;
function GetThis(const pr: TSimpleMethod): TObject;
begin
Result := TMethod(pr).Data;
end;
// usage:
with TStringList.Create do
try
CommaText := '1,2,3,4,5,6,7,8,9,0';
ShowText(TStringList(GetThis(Free)));
finally
Free;
end;
or class helpers:
type
TObjectHelper = class helper For TObject
private
function GetThis: TObject; Inline;
public
property This: TObject read GetThis;
end;
...
function TObjectHelper.GetThis: TObject;
begin
Result := Self;
end;
But, actually, previous replies are correct: you should better forget about "with" statement.
回答2:
You should never use with
either because future changes might introduce more into that scope than you intended.
Take this for instance:
procedure Test;
var
x: Integer;
begin
with TSomeObject.Create do
begin
DoSomethingWithX(x);
Free;
end;
end;
and then later on you tuck on a X property on the TSomeObject class. Now, which X do you think it's going to use? The local variable or the X property of the object?
The best solution is always to just create a local variable with a short name, and alias the object to that variable.
procedure Test;
var
x: Integer;
o: TSomeObject;
begin
o := TSomeObject.Create;
o.DoSomethingWithX(x);
o.Free;
end;
回答3:
You gave the answer yourself: declare local variable. If you want you can use the with keyword on that.
var
MyInstance: TMyObject;
begin
MyInstance := TMyObject.Create;
with MyInstance do
try
Foo;
Bar;
DoSomething(MyInstance);
finally
Free;
end;
end;
In above example the only reason to use with is code readability, which is very subjective, you could also ditch the with keyword and use MyInstance directly. It's just a matter of personal taste. I don't agree on the "never use with" answers, but you should be aware of it's drawbacks.
See also this question: Is delphi "with" keyword a bad practice?
回答4:
An addition to Brian's example on a Notify handler is to use an absolute variable (win32 only):
procedure Notify( Sender : TObject );
var
Something : TSomeThing absolute Sender;
begin
if Sender is TSomething then
begin
VerySimpleProperty := Something.Something;
OtherProperty := Something.SomethingElse;
end;
end;
It basically avoids having to assign a local variable or have a lot of type casts.
回答5:
I've learnt the hard way - only use 'With' in the following scenarios:
With TMyForm.Create( Owner ) do
try
ShowModal
finally
Free;
end;
procedure Notify( Sender : TObject );
begin
With Sender as TSomething do
VerySimpleProperty := Something
end;
i.e keep the visibility of With as simple as possible. When you take into account the fact that the debugger cant resolve 'With', it's actually better and clearer to use a simple local variable or to fully declare the target i.e MyRecord.Something
回答6:
This is not possible now, but we can make it a reality by persuading the compiler creators:
With TForm1.Create (Nil) Do // New TForm1 instance
Try
LogForm ("); // That same instance as parameter to an outer method (solution)
"ShowModal; // Instance.ShowModal
Finally
"Free; // Instance.Free
End;
My proposal is:
- No more than one object/record per With header.
- Nested Withs not allowed.
- Usage of " to indicate the object/record (double quotes are similar
to the ditto mark: http://en.wikipedia.org/wiki/Ditto_mark).
回答7:
There is a working fine hack to do so.
Define this workaround function somwhere in project unit.
// use variable inside 'with ... do'
// WSelf function returns TObject associated with its method.
// I would recommend to use the method 'Free'
// WSelf(Free) as <TObjectN>
type TObjectMethod = procedure of object;
function WSelf(const MethodPointer: TObjectMethod): TObject;
begin
Result := TMethod(MethodPointer).Data;
end;
Usage example.
var
SL: TStringList;
begin
SL := TStringList.Create;
try
with TStringList.Create do
try
Add('1');
Add('2');
Add('3');
// (WSelf(Free) as TStringList) references to the object
// created by TStringList.Create
SL.Assign(WSelf(Free) as TStringList);
finally
Free;
end;
finally
ShowMessage(SL.Text);
SL.Free;
end;
end;
回答8:
You should use Self
.
Example:
with TAnObject.Create do
begin
DoSomething(Self);
end;
In that context Self
is the object created by with
clause.