2009-04-26 14 views
7

¿Hay alguna manera de hacer referencia a una instancia de objeto que se crea con la instrucción "con"?Instancia de objeto de referencia creada con "con" en Delphi

Ejemplo:

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

Dónde HacerAlgo usaría la referencia de instancia como si estuviera pasando una instancia de una variable declarada referencia al objeto creado.

Ejemplo:

AnObject := TAnObject.Create; 

Gracias.

Respuesta

12

Nunca debe usar with ya sea porque los cambios futuros podrían introducir más en ese ámbito de lo previsto.

dar esto por ejemplo:

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

y más tarde que meter en una propiedad de la clase X en TUnObjeto. Ahora, ¿qué X crees que va a usar? La variable local o la propiedad X del objeto?

La mejor solución es siempre crear una variable local con un nombre corto y alias el objeto a esa variable.

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

véase también http://stackoverflow.com/questions/71419/whats -wrong-with-delphis-with –

+0

Ok, voy a morder :-) 'with' puede causar una gran confusión si no tienes cuidado, pero hay situaciones en las que simplemente hace que el código sea mucho más legible. Los nombres cuidadosos pueden ser de ayuda aquí. El uso de esquemas de nombres para evitar confusiones es una técnica común para el código Delphi de todos modos (use TXxx para tipos, FXxxx para miembros privados, GetXxx y SetXxx para getters y setters, etc.). Simplemente use MyXxx o algo similar para las variables locales y no tendrá tanta confusión como lo haría al llamar a las variables "x" y "o". –

+1

No cambiaría los pocos casos en los que * podría * hacerlo más legible para esas ocasiones en las que la función de auto-alcance me ha mordido. Literalmente he desperdiciado semanas en problemas relacionados con esto. Ningún código puede justificarse por ser tan legible que vale tanto tiempo para encontrar errores extraños. –

14

Bueno, puede utilizar este enfoque:

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

o de clase ayudantes:

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; 

Pero, en realidad, las respuestas anteriores son correctas: usted debe mejor olvidarse de "con" declaración.

+1

+1 :) Ninguna de estas cosas de ayuda existió mucho tiempo atrás cuando originalmente estaba haciendo Delphi. – cgp

+5

+1 para uso insano de Delphi :)) ¡Genial! – gabr

+0

Gracias: D – Alex

1

que he aprendido de la manera difícil - sólo uso 'con' en los siguientes escenarios:

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


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

es decir mantener la visibilidad de Con tan simple como sea posible. Cuando se tiene en cuenta el hecho de que el depurador no puede resolver 'Con', en realidad es mejor y más claro utilizar una variable local simple o declarar completamente el objetivo, es decir, MyRecord.Something

3

Usted mismo ha respondido: declare la variable local . Si lo desea, puede usar la palabra clave con en eso.

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

En el ejemplo anterior la única razón para usar con es la legibilidad del código, que es muy subjetiva, también puede deshacerse de la con palabra clave y utilizar MyInstance directamente. Es solo una cuestión de gusto personal. No estoy de acuerdo con las respuestas "nunca usar con", pero debe tener en cuenta sus inconvenientes.

Ver también esta pregunta: Is delphi "with" keyword a bad practice?

2

Una adición al ejemplo de Brian en un manejador de Notify es utilizar una variable absoluta (sólo 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; 

Básicamente evita tener que asignar una variable local o tiene una gran cantidad de moldes tipo.

+0

+1 por asistirnos sobre el uso de 'absolute' (que hace mucho tiempo se introdujo para referencias absolutas de memoria, pero su ejemplo es el único uso que es compatible tanto con .net como con el mundo nativo). –

+0

Utilizo mucho esta construcción, pero recientemente me he dado cuenta de que se mezcla con el optimizador del compilador.El uso de este tipo de constructo puede, por lo tanto, conducir a una generación de código ineficiente, en caso de que esto sea importante (pero puede conducir a un código más fácil de leer, IMO, en caso de que la velocidad no sea importante). – HeartWare

1

esto no es posible ahora, pero podemos hacer que sea una realidad al convencer a los creadores del compilador:

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; 

Mi propuesta es:

  1. No más de un objeto/registro por Con cabecera .
  2. Anidado No permitido.
  3. El uso de "para indicar el objeto/registro (comillas dobles son similares hasta la marca de ídem: http://en.wikipedia.org/wiki/Ditto_mark)..
0

Hay un truco funciona bien para hacerlo definir esta función solución somwhere en proyecto unidad.

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

ejemplo de uso.

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; 
Cuestiones relacionadas