在Delphi中使用“with”创建的引用对象实例

问题描述 投票:0回答:9

有没有办法引用使用“with”语句创建的对象实例?

示例:

with TAnObject.Create do
begin
  DoSomething(instance);
end;

DoSomething 将使用实例引用,就像将实例从声明的变量引用传递给创建的对象一样。

示例:

AnObject := TAnObject.Create;

谢谢。

delphi with-statement
9个回答
17
投票

那么,你可以使用这样的方法:

// 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;

或班级助手:

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;

但是,实际上,之前的回复是正确的:你最好忘记“with”语句


12
投票

您也不应该使用

with
,因为未来的更改可能会比您预期的范围引入更多内容。

以这个为例:

procedure Test;
var
    x: Integer;
begin
    with TSomeObject.Create do
    begin
        DoSomethingWithX(x);
        Free;
    end;
end;

然后稍后您将 X 属性塞到 TSomeObject 类上。现在,您认为它将使用哪个 X?局部变量还是对象的 X 属性?

最好的解决方案始终是创建一个具有短名称的局部变量,并将对象别名为该变量。

procedure Test;
var
    x: Integer;
    o: TSomeObject;
begin
    o := TSomeObject.Create;
    o.DoSomethingWithX(x);
    o.Free;
end;

4
投票

你自己给出了答案:声明局部变量。如果您愿意,可以使用 with 关键字。

var
  MyInstance: TMyObject;
begin
  MyInstance := TMyObject.Create;
  with MyInstance do
  try
    Foo;
    Bar;
    DoSomething(MyInstance);
  finally
    Free;
  end;
end;

在上面的示例中,使用 with 的唯一原因是代码可读性,这是非常主观的,您也可以放弃 with 关键字并直接使用 MyInstance。这只是个人品味问题。我不同意“永远不要与…一起使用”的答案,但你应该意识到它的缺点。

另请参阅这个问题:delphi“with”关键字是一种不好的做法吗?


2
投票

Brian 关于通知处理程序的示例的补充是使用绝对变量(仅限 win32):

procedure Notify( Sender : TObject ); 
var 
  Something : TSomeThing absolute Sender;
begin 
  if Sender is TSomething then 
  begin
    VerySimpleProperty := Something.Something;
    OtherProperty := Something.SomethingElse;
  end;
end;

它基本上避免了分配局部变量或进行大量类型转换。


1
投票

我经历了惨痛的教训 - 仅在以下场景中使用“With”:

With TMyForm.Create( Owner ) do
  try
    ShowModal
  finally
    Free;
  end;


procedure Notify( Sender : TObject );
begin
  With Sender as TSomething do
    VerySimpleProperty := Something      
end;

即保持 With 的可见性尽可能简单。当您考虑到调试器无法解析“With”这一事实时,使用简单的局部变量或完全声明目标(即 MyRecord.Something)实际上更好、更清晰


0
投票
有一个很好的技巧可以做到这一点。 在项目单元中的某处定义此解决方法函数。

// 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;

使用示例。

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;
    

0
投票
对于 FMX,您应该使用 GetObject 示例:

with TLabel.Create(box1) do begin Font.Size := 34; Font.Style := [TFontStyle.fsBold]; TextAlign := TTextAlign.taCenter; box1.AddObject(GetObject); end;;
    

0
投票
Delphi 中最好的方法是使用变量来处理该实例。


-1
投票
现在这是不可能的,但我们可以通过说服编译器创建者使其成为现实:

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;

我的建议是:

    每个 With header 不得超过一个对象/记录。
  1. 不允许嵌套。
  2. 使用“来指示对象/记录(双引号类似 到同上标记:
  3. http://en.wikipedia.org/wiki/Ditto_mark)。
© www.soinside.com 2019 - 2024. All rights reserved.