Tutorial :Reference object instance created using “with” in Delphi



Question:

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.


Solution: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.


Solution: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;  


Solution: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?


Solution: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.


Solution: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


Solution: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:

  1. No more than one object/record per With header.
  2. Nested Withs not allowed.
  3. Usage of " to indicate the object/record (double quotes are similar to the ditto mark: http://en.wikipedia.org/wiki/Ditto_mark).


Solution: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;  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »