Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 12-08-2006
Avatar de xEsk
[xEsk] xEsk is offline
Miembro Premium
 
Registrado: feb 2006
Posts: 454
Poder: 19
xEsk Va por buen camino
Duplicar "objetos"

Hola.

A ver, os explico el tema, puede q la pregunta sea muy estupida (pero no habia usado hasta hace poco la POO en delphi xD).

La cosa esq tengo un objeto propio, q no es nativo del delphi, como por ejemplo:

Código Delphi [-]
TMyClass = class   
// codigo 
end;

o

Código Delphi [-]
TMyObject = class (TObject)   
// codigo 
end;

Y quiero duplicarlo, osea crear 2 objetos iguales pero q sean independientes. Lo q esta claro esq si hacemos algo parecido a esto:


Código Delphi [-]
var   
  obj1, obj2: TMyObject;  

begin   
  obj1:=TMyObject.Create;   
  obj1.Propiedad:='Hola Caracola!';     
  obj2:=obj1;     
  obj1.Free;   
  ShowMessage(obj2.Propiedad); // Resultado = ''  (nada)   
  obj2.Free; // Error: Invalid pointer operation


Ok, esto es normal q pase, ya q lo unico q hace es q el obj2 copia el puntero de obj1, y q si liberamos el obj1, el obj2 por asociacion se libera tambien, pero mi pregunta viene aqui: ¿Como lo hago para crear un objeto duplicado identico pero independiente uno del otro?

He buscado por el foro, "copiar objeto", y me ha salido un post parecido a este, pero era para copiar Componentes visuales, y una de las respuestas me dio una idea, y es el "Assign", pero claro mis clases no tienen este proceso. ¿Deberia implementarla o heredarla de un objeto de nivel mas alto? ¿Hay alguna solucion facil y q no sepa q existe (q seria lo mas seguro xD)?

Ahi va el tema, gracias por adelantado.

Saludos.
Responder Con Cita
  #2  
Antiguo 12-08-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Reconozco que saco la frase de contexto, pero, es que me intriga de veras: ¿a qué te refieres cuando dices...

Cita:
(...) duplicarlo, osea crear 2 objetos iguales pero q sean independientes
¿Qué entiendes por dos objetos iguales? ¿Dos instancias de una misma clase? ¿Pero no son independientes entonces?
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #3  
Antiguo 12-08-2006
Avatar de xEsk
[xEsk] xEsk is offline
Miembro Premium
 
Registrado: feb 2006
Posts: 454
Poder: 19
xEsk Va por buen camino
A mi tb me costo escribirlo, a ver si puedo definirlo de otra forma, hehe

Me refiero a q se cree una segunda instancia, q sea una copia de la primera (vamos con los mismos valores) pero q si elimino la primera, esta segunda (la nueva) no se vea afectada de ninguna forma y siga funcionando tranquilamente.

No se si me he explicado mejor (en mi cabeza lo tengo muy claro, pero me cuesta definirlo de una forma q se entienda bien xDD)

El mismo ejemplo, pero mostrado de otra forma:
Código Delphi [-]
var
  obj1, obj2: TMyObject;
  puntero1, puntero2: Pointer;

begin
  obj1:=TMyObject.Create;   
  puntero1:=obj1;
  obj2:=obj1; 
  puntero2:=obj2;

  if puntero1 = puntero2 then
    ShowMessage('Vaya, apuntamos al mismo sitio de memoria!!');    

  obj1.Free;
  // El obj2, no hace falta liberarlo... xD

Saludos.

Última edición por xEsk fecha: 12-08-2006 a las 16:33:59.
Responder Con Cita
  #4  
Antiguo 12-08-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Bueno. Ahora creo haberte entendido. Me parece que el concepto sería "clonar" un objeto. Al menos así lo entiendo yo desde que conozco (a medias) la interface "ICloneable" disponible en la clase "System" de la plataforma .NET. En esta página (Delphi Basics) se trata sobre dicha interfaz, y, creo que la misma consigue está ahí para echar una mano a lo que te propones.

Empero,... la verdad es que yo me pierdo un poco hablando de estos temas. A mí se me ocurre que si el objeto que quieres "clonar" no es muy "complejo", el mismo podría contar con un método (especificado o no por alguna interfaz al uso, que no sé si existe en Delphi, o si merecería la pena, si se ganaría algo), que el objeto contara con un método, digo, que fuera el encargado de la tarea que nos ocupa.

Yo imagino algo así, pero, intuyo que podría mejorarse mucho, que me meto en temas que no comprendo bien. Parece ser que en esto de clonar objetos puede tirarse por dos caminos:

Cita:
A shallow copy of a collection copies only the elements of the collection, whether they are reference types or value types, but it does not copy the objects that the references refer to. The references in the new collection point to the same objects that the references in the original collection point to.


In contrast, a deep copy of a collection copies the elements and everything directly or indirectly referenced by the elements.
Y dependerá, como digo, de la "complejidad" del objeto que quieras clonar. A mí, con un objeto creado para la ocasión y muy sencillo, me sale algo así:

Código Delphi [-]
interfaz

type
  TObjeto = class
  private
    FVariable: string;
  public
    function Clonar(var destino: TObjeto) : boolean;
  public
    property Propiedad: string read FVariable write FVariable;
  end;

implementation

{ TObjeto }

function TObjeto.Clonar(var destino: TObjeto): boolean;
begin
  destino.Propiedad := Self.FVariable;
  Result := true;
end;

Una prueba podría resultar más o menos esto:

Código Delphi [-]
var
  objeto, objeto2: TObjeto;
begin
  objeto := TObjeto.Create;
  objeto.Propiedad := 'Una cadena';

  objeto2 := TObjeto.Create;
  objeto.Clonar(objeto2);

  objeto.Free; // Liberamos

  // Pero objeto2 hace las veces de objeto
  ShowMessage(objeto2.Propiedad);

  objeto2.Free;
end;
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #5  
Antiguo 12-08-2006
Avatar de xEsk
[xEsk] xEsk is offline
Miembro Premium
 
Registrado: feb 2006
Posts: 454
Poder: 19
xEsk Va por buen camino
Hola.

Antes q nada, gracias por perder tu precioso tiempo conmigo.

Si, tienes razon q seria mucho mas sencillo llamarlo clonar.
Tu solucion es una de mis primeras pensadas, pero luego como tu bien resaltas, si no son objetos complejos, cosa q no es el caso, heheh (vaya mala pata xD), ya q la clase q quiero clonar tiene bastantes propiededes, q a su vez estas tambien son clases con sus propiedades.

Por el momento, la solucion mas cutre q se me ocurre, es intentar eviatar la necesidad de clonar.

Despues de escribir este mensaje voy a leer el link q me has pasado.

Saludos.
Responder Con Cita
  #6  
Antiguo 12-08-2006
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 28
Lepe Va por buen camino
Pues si es complejo... a lo facil.

Deriva de TComponent que ya tienes los métodos Assign. Eso sí, deberás mirar como manipulas memoria dentro de tu objeto, pero en principio sería algo asi:

Código Delphi [-]
type TMyClass = Class(Tcomponent)
// el codigo
end;

var o1, o2 : TMyClass;
begin
o1 := TMyClass.Create;
o1.propiedad := 'mio';
o2 := TMyClass.Create;
o2.Assign(o1);
// ahora si, tenemos 2 objetos distintos.
end;

Si indagas por la VCL y la ayuda de Assign, creo que te puede hacer la vida más fácil.

Alguna vez, para guardar un objeto en disco con SaveToStream, simplemente cambié el TObject por TComponent y todo resuelto, aunque creo que para tí no será tan simple.

Saludos
__________________
Si usted entendió mi comentario, contácteme y gustosamente,
se lo volveré a explicar hasta que no lo entienda, Gracias.
Responder Con Cita
  #7  
Antiguo 12-08-2006
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Cita:
Empezado por Lepe
Deriva de TComponent que ya tienes los métodos Assign.
"TPersintent" es la primera clase que cuenta con un método "Assing":

Cita:
Empezado por Ayuda de Delphi
TPersistent is the ancestor for all objects that have assignment and streaming capabilities.
Pero hay que seguir un poco más adelante, en la misma ayuda:

Cita:
Empezado por Ayuda de Delphi
TPersistent encapsulates the behavior common to all objects that can be assigned to other objects, and that can read and write their properties to and from a form file (.xfm or .dfm file). For this purpose TPersistent introduces methods that can be overridden to:

Define the procedure for loading and storing unpublished data to a stream.
Provide the means to assign values to properties.
Provide the means to assign the contents of one object to another.

Do not create instances of TPersistent. Use TPersistent as a base class when declaring objects that are not components, but that need to be saved to a stream or have their properties assigned to other objects.
Pero, hasta donde yo llego, cuando derives de "TComponent" no estás utilizando ningún método "Assing" de esta clase, porque la misma no cuenta con él (no lo sobreescribe), sino que se usa el método "Assing" de la clase "TPersintent", de la que hereda "TComponent".

Léase la ayuda del método "Assing" de "TPersistent", pero, vamos aquí a ver el código fuente de dicho método:

Código Delphi [-]
procedure TPersistent.Assign(Source: TPersistent);
begin
  if Source <> nil then Source.AssignTo(Self) else AssignError(nil);
end;

Es decir... (atreviéndome un poco y por lo que he entendido en la ayuda), se averigua primero si el objeto "origen" no es "nil", y, en caso de que no sea "nil" se llama al método "AssingTo" del propio objeto "origen". En caso contrario se produce un error.

Continuemos con el método "AssingTo", que se encuentra también la clase "TPersistent" declarado como un método protegido y virtual. ("Assing" está declarado como virtual también, pero es un método público). Este es el código fuente del método "AssingTo" de la clase "TPersistent":

Código Delphi [-]
procedure TPersistent.AssignTo(Dest: TPersistent);
begin
  Dest.AssignError(Self);
end;

No sé qué les parecerá a ustedes, pero, me parece que se está queriendo decir: "no debes llamar a este método desde un objeto "TPersistent", sino desde algún objeto que implemente este método virtual, más aún, no debes llamar a "AssingTo", directamente, sino que llama al método "Assing", que ya se encargará de llamarme a mí.".

Casi termino diciendo que no sabré dar una solución, como no sea por aproximación y según escribo esto, pero, si derivas un objeto de "TComponent", como si lo derivas de "TPersistent", no harás sino producir un error si llamas al método de dicho objeto "Assing", puesto ya hemos visto que "TPersistent" quiere (al declararlos como virtuales) que sean las clases derivadas de ella las que implementen los métodos "Assing" y "AssingTo".

Como "TComponent" no implementa dichos métodos virtuales, aunque deriva de "TPersistent", resulta que algo como esto deriva en una excepción de tipo "EConvertedError":

Código Delphi [-]
type
  TObjeto = class(TComponent)
  private
    FVariable: string;
  public
    property Propiedad: string read FVariable write FVariable;
  end;

implementation

{$R *.dfm}


procedure TForm1.FormCreate(Sender: TObject);
var
  objeto, objeto2: TObjeto;
begin
  objeto := TObjeto.Create(Self);
  objeto.Propiedad := 'Una cadena';

  objeto2 := TObjeto.Create(Self);
  objeto2.Assign(objeto); // EConvertError

  objeto.Free; // Liberamos
  objeto2.Free;
end;

Código Delphi [-]
type
  TObjeto = class(TPersistent)
  private
    FVariable: string;
  public
    property Propiedad: string read FVariable write FVariable;
  end;

implementation

{$R *.dfm}


procedure TForm1.FormCreate(Sender: TObject);
var
  objeto, objeto2: TObjeto;
begin
  objeto := TObjeto.Create;
  objeto.Propiedad := 'Una cadena';

  objeto2 := TObjeto.Create(Self);
  objeto2.Assign(objeto); // EConvertError

  objeto.Free; // Liberamos
  objeto2.Free;
end;

¿Y entonces? ¿Cómo podemos clonar un objeto, duplicarlo o como lo queramos llamar? Pues a mí después de todo esto que he escrito para ver si me daba alguna idea, no me queda sino pensar en que los objetos a clonar deben implementar por su cuenta los métodos "Assing" y "AssingTo", y derivar de "TPersistent", directa o indirectamente.

Así que, no sé yo de qué objetos estamos hablando, pero, la clonación de un objeto a mí no me parece nada sencilla. Claro que yo de esto entiendo más bien poco, pero, si lo que he dicho tiene algún sentido, los objetos, las propiedades que fueran a su vez objetos, tendrían que contar con métodos "Assing" y "AssingTo", como digo, y además estaría aquello de tener que decidir entre las dos opciones que parece que hay, como poco:

Cita:
Empezado por De la ayuda de la interfaz ICloneable en la plataforma .NET
A shallow copy of a collection copies only the elements of the collection, whether they are reference types or value types, but it does not copy the objects that the references refer to. The references in the new collection point to the same objects that the references in the original collection point to.

In contrast, a deep copy of a collection copies the elements and everything directly or indirectly referenced by the elements.
O sea, que vais a tener que perdonarme el rollo que acabo de soltar, porque, desde luego no me atrevo, sin saber más del tema en concreto que tratamos (tipos de objetos, etc.) a dar una solución sencilla. Algún compañero quizás vea esto de otro modo menos embrollado que como yo lo veo.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #8  
Antiguo 13-08-2006
Mick Mick is offline
Miembro
 
Registrado: may 2003
Posts: 405
Poder: 21
Mick Va por buen camino
Confirmo que lo que ha dicho Dec es correcto, para una clase definida por
el programador, es el propio programador el que debe crear el metodo que clone el objeto, es imposible que esto se haga de forma automatica, porque
dado un objeto mas o menos complejo, realmente podria haber varias formas distintas de clonarlo.

Cualquier objeto suele tener definidas propiedades o variables que apuntan a a su vez otros objetos.

Cuando se quiere clonar el objeto estas propiedades o variables, hay que mirarlas una por una y decidir si tambien hay que clonarlas o no.

Habra propiedades que si tendremos que clonar y otras que no porque son comunes para todas las instancias, incluso puede haber otras propiedades que no estaria claro si hay que clonarlas.

Por ejemplo si tenemos un objeto con una propiedad "parent" que hace referencia a un objeto "padre", esta claro que esta propiedad no se debe clonar y duplicar en el objeto nuevo, luego quizas el objeto clonado deberia mantener una referencia al mismo "parent", o quizas tambien tenemos otra opcion que es crear el objeto clonado sin padre, con valor nulo, asi que tendra que decidir el programador que es lo mas adecuado.

Otro ejemplo, si dentro de un objeto tenemos una variable que hace referencia a un objeto TScreen, en un objeto clonado tendriamos que mantener exactamente el mismo objeto ya que solo puede existir un unico objeto TScreen en una aplicacon de delphi (este objeto hace referencia a la pantalla de Windows que normalmente solo hay una).

Saludos
Responder Con Cita
  #9  
Antiguo 14-08-2006
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Smile Con _CopyRecord, pero...

¡Hola a todos!

He leído con interés el tema sin poder evitar remontarme a marzo de 2000, cuando buscaba algo similar a lo planteado por xEsk. En aquel entonces, indagando en la unidad System.pas de Delphi 3 o 4 (no recuerdo la versión exacta), encontré un par de funciones que llamaron mucho mi atención: _CopyRecord y _CopyObject (si, la “famosa” _CopyObject, el mayor misterio de la unidad System). Bien, resulta que sí es posible hacer una clonación superficial (shallow) o profunda (deep) —con mucho más esfuerzo— de un objeto en Delphi Win32, sin importar su clase, sin tener que redefinir la implementación de métodos como Assign o AssignTo. Pero el precio es, digamos, bastante incómodo.

Habiendo aprendido que las funciones de la bien llamada magia del compilador, cuyos nombres inician con un guión bajo (“_”), y que generalmente fueron escritas en lenguaje ensamblador, son las rutinas que el compilador encadena como resultado de ciertas sentencias de código fuente, me pregunté «¿dónde utiliza el compilador la función _CopyRecord?». Encontrar la respuesta no fue difícil. Cada vez que el compilador encuentra una sentencia como «Registro1 := Registro2;», siendo Registro1 y Registro2 dos variables de un mismo tipo record (llamado struct en otros lenguajes), el código máquina resultante es una llamada a la función _CopyRecord, la cual recibe como parámetros el registro destino, el registro origen y la información estructural del tipo de dato:

Cita:
Empezado por Borland
Código Delphi [-]
procedure       _CopyRecord{ dest, source, typeInfo: Pointer };
_CopyRecord utiliza la información estructural dada por el tercer parámetro para copiar adecuadamente los campos de la estructura origen a la estructura destino. El proceso sería relativamente simple si no existieran los jóvenes tipos de datos que requieren un tratamiento especial (cadenas largas, variantes, arreglos dinámicos e interfaces). _CopyRecord copia el valor de todos los bytes del bloque de memoria origen al bloque destino, pero también realiza llamadas a otras funciones mágicas como _LStrAsg, _WStrAsg, _VarCopy, _IntfCopy, y _DynArrayAsg (me permito un comentario al estilo de Ian Marteens: ¿acaso pretenden con esos nombres ahorrarnos memoria en el disco duro? ) para copiar adecuadamente los campos que llevan contadores de referencia o que, por su naturaleza, necesitan un manejo especial. Gracias a esta función, es relativamente fácil para el programador clonar superficialmente una estructura Record, una simple sentencia de asignación basta.

Entonces, la siguiente pregunta que me hice fue «¿dónde utiliza el compilador la función _CopyObject?»...Llevo cinco años preguntándome lo mismo. La intriga resulta de analizar tres cosas:

1. En el código fuente de todas las unidades nativas de Delphi no hay una sola referencia a la función _CopyObject.
2. Aparentemente, no hay ninguna sentencia Object Pascal que se pueda considerar traducible como una llamada a esta función («Objeto1 := Objeto2;» no vale, es una simple copia de puntero; «Objeto1^ := Objeto2^;» tampoco, ya que el compilador no permite esa sintaxis con variables objeto).
3. Curiosamente, _CopyObject llama a la función _CopyRecord, pero sólo una vez. Lo cual significa que sólo clona los campos del objeto que hayan sido directamente declarados por una clase. Para clonarlo por completo, habría que llamar a _CopyRecord por cada una de las clases involucradas en la jerarquía del objeto a copiar.

Menciono lo anterior en base a las pruebas que realicé en aquel entonces. Ante esto, veo tres posibles respuestas a la intriga:

1. Que la función _CopyObject es utilizada para asignaciones de variables objeto object (clases estilo Turbo Pascal), no class.
2. Que la función _CopyObject es utilizada desde afuera, por algún lenguaje compatible con Delphi, como C++ Builder.
3. Que la función _CopyObject sea una asignatura pendiente, algo dejado a medias en la unidad System.pas.

Habría que hacer algunas pruebas e indagaciones adicionales para develar el misterio.

Admito que no sé mucho de lenguaje ensamblador, por lo que expongo aquí una copia de la función _CopyObject de Delphi 7 (que me parece no ha variado desde entonces). Si alguno de los lectores es ducho en el tema y tiene la gentileza de explicarnos cómo entiende este código fuente, más de un programador “paranoico” le estaremos agradecidos.

Código Delphi [-]
 
procedure       _CopyObject{ dest, source: Pointer;
  vmtPtrOffs: Longint; typeInfo: Pointer };
asm
        { ->    EAX pointer to dest             }
        {       EDX pointer to source           }
        {       ECX offset of vmt in object     }
        {       [ESP+4] pointer to typeInfo     }

        ADD     ECX,EAX                         { pointer to dest vmt }
        PUSH    dword ptr [ECX]                 { save dest vmt }
        PUSH    ECX
        MOV     ECX,[ESP+4+4+4]
        CALL    _CopyRecord
        POP     ECX
        POP     dword ptr [ECX]                 { restore dest vmt }
        RET     4

end;

(el código de _CopyRecord y otras funciones mágicas puede ser visto en el archivo System.pas de muchas versiones de Delphi).

¿Logré clonar objetos en aquella aventura? Si. ¿Cómo lo hice? Basándome en el código de la rara función _CopyObject, creando una nueva función que encapsulara y llamara iterativamente a la función _CopyRecord por cada clase existente en la jerarquía del objeto a clonar.

Aquí el código de mi función:

Código Delphi [-]
  Function CopiaObje (Const ObjeOrig, ObjeDest :TObject) :Boolean;
  Var
    { Clase Auxiliar y Clase del Objeto Destino }
    ClasAuxi, ClasObjeDest :TClass;
  Begin
    { Si alguno de los dos objetos dados no es válido }
    If Not BooleanCopiBuff (SonPuntVali ([ObjeOrig, ObjeDest]),
                            Result) Then
      Exit;

    { Guardar la Clase de ObjeDest.  NOTA: Los objetos dados pueden ser
      de diferente clase, pero deben tener estructuras equivalentes.    }
    ClasObjeDest := ObjeDest.ClassType;


    { Realizar copias que incrementen y decrementen, los contadores de
      referencia de los campos de tipo cadena, variante e interfaz     }

    ClasAuxi := TObject;

    Repeat
      { Asignarle a ClasAuxi la siguiente clase hija que Desciende
        hacia la clase del Objeto Origen                           }
      DesceClas (ClasAuxi, ObjeOrig.ClassType);

      { Si la clase actual cuenta con Información de Inicialización }
      If InforInicClas (ClasAuxi) <> Nil Then
        { Usarla para el copiado incrementador/decrementador de
          contadores de referencia de campos                    }
        _CopyRecord (ObjeDest, ObjeOrig, InforInicClas (ClasAuxi));
    Until ClasAuxi = ObjeOrig.ClassType;


    {******************************************************************}
    { Asegurar que sea Copiado todo el bloque de memoria de la         }
    { instancia Origen, ya que _CopyRecord pudo no haberse ejecutado o }
    { pudo haber dejado bytes finales sin copiar.  NOTA: La causa de   }
    { que _CopyRecord deje bytes finales sin copiar, es que la         }
    { estructura devuelta por InforInicClas, no es exactamente igual a }
    { la estructura devuelta por la función TypeInfo, cuando es        }
    { aplicada a un tipo registro.                                     }
    {******************************************************************}
    CopiaBuff (Pointer (ObjeOrig)^, Pointer (ObjeDest)^,
               TamaoObje (ObjeOrig));

    { Restaurar la Clase del Objeto Destino }
    PClass (ObjeDest)^ := ClasObjeDest;
  End;

Varias de las funciones de biblioteca referenciadas pueden ser sustituidas sin muchos problemas por llamadas a funciones nativas (pido disculpas por el robótico estilo que empleaba hasta hace pocos años ), y así obtener una función clonadora de objetos.

Pero quien ya se haya puesto a trabajar en esto se topará con una interrogante final: «¿Cómo hago para llamar a la función _CopyRecord?». Ahí estuvo el principal obstáculo. _CopyRecord es una función interna de System.pas, no puede ser referenciada explícitamente en el código fuente de otra unidad. Lo primero que se me ocurrió fue crear una nueva unidad y poner ahí una copia de la función _CopyRecord, pero de inmediato descarté ese camino, ya que _CopyRecord llama directa e indirectamente a un buen número de otras funciones internas. Así que la solución más práctica que encontré fue clonar (hablando de) la unidad System.pas, creando mi propia "System2.pas” con una función _CopyRecord perfectamente declarada para poder ser utilizada desde afuera.

Código Delphi [-]
Unit System2;

Interface

  Procedure _CopyRecord (Dest, Source, TypeInfo :Pointer);

Para crear un objeto clon, un ejemplo podría ser:

Código Delphi [-]
Begin
  { Crear una instancia en blanco de la misma clase que ObjetoOrigen }
  Clon := ObjetoOrigen.ClassType.Create;

  Try
    { Habiendo creado un nuevo objeto en blanco, copiarle los campos de
      la instancia a la que apunta ObjetoOrigen }
    CopiaObje (ObjetoOrigen, Clon);
  Except  { Si se eleva una excepción }
    Clon.Free;  { Liberar la instancia creada }
    Raise;  { Reelevar la excepción }
  End;

De esta forma sí es viable clonar objetos en Delphi no .NET, y, como se puede ver, el precio resulta incómodo. Desaconsejo esta chapucera práctica de robarle el código privado a System.pas porque uno nunca sabe cuándo Borland decidirá hacer un cambio que teóricamente no debería afectar al programador. Además, se presentan muchos problemas cuando se trata de clonar objetos que tienen reglas de negocio relacionadas con la asignación de valores a sus propiedades (la clonación las pasa por alto), cuando los objetos guardan referencias a otros objetos, y, peor aún, cuando esas referencias son simples identificadores (handles) a objetos de alguna API (como es el caso de la mayoría de los componentes visuales). La clonación puede resultar desde inestable hasta caótica.

Quizá por eso Borland decidió suspender o reservarse la función _CopyObject. O quizá pensaron «Debemos estudiar mejor este asunto, tal vez en el futuro nos pongamos de acuerdo los fabricantes para establecer un estándar de clonación controlada. No le pongamos clonación a Delphi todavía, esperemos mejores tiempos, veamos primero cómo les resulta a otros...».

Java se aventuró a incluir esta característica y al parecer Microsoft, tarde, aunque nada perezoso, reinventó el hilo negro llamándolo interfaz ICloneable de .NET.

Sólo me resta decir que sugiero manejar con reserva primitivos métodos de clonación como el que expuse. Personalmente, la experiencia vivida me resultó más un ejercicio de aprendizaje que una solución a problemas importantes. Tal vez xEsk debería hablarnos de cuál es el objetivo concreto que persigue para proponerle mejores alternativas.

Ah, y aún tengo la esperanza de que alguien me explique la función _CopyObject.

Un abrazo clonado.

Al González.

Última edición por Al González fecha: 14-08-2006 a las 00:59:13.
Responder Con Cita
  #10  
Antiguo 17-08-2006
Avatar de xEsk
[xEsk] xEsk is offline
Miembro Premium
 
Registrado: feb 2006
Posts: 454
Poder: 19
xEsk Va por buen camino
Al González, muy interesante tu respuesta... sin duda.
Por el momento lo he solucionado, evitando la clonacion, y me funciona bien.

El motivo por el cual queria clonar objetos, es pq este objeto (junto con algunas de sus propiedades) necesitan de internet para rellenar sus propiedades, y bajarase 4 (o mas) veces la misma informacion para cambiar solo un par de propiedades, me parecia exagerado, asi q pense en clonar el objeto con la informacion ya bajada y luego cambiarle esas pocas propiedades, optimizando asi la velocidad...

Gracias a todos por las respuestas.

P.D.: Perdon por tardar en responder, he estado ocupado esos dias.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
¿cuál es mejor: "close" o "application.terminate"? unreal4u Varios 5 05-03-2007 11:01:19
porque no me reconoce los caracteres "*" ni "%" cuando filtro mrmago Conexión con bases de datos 10 27-01-2006 04:21:16
Compartir "objetos" entre varias instancias mafebresv Varios 4 16-01-2006 23:38:23
Tipo de Variable."String" ó "Double" UTECYBER OOP 7 15-12-2003 20:25:39


La franja horaria es GMT +2. Ahora son las 16:44:32.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi