Hola Juan:

Muy buen ejemplo. Nunca me había pasado, supongo que porque nunca separé la
creación de los eventos access y assign.

Igualmente, si tu primer ejemplo "bueno" lo ejecutás más de una vez,
también da error, ya que el bug tiene que ver con la carga y cacheo de la
definición de las clases en memoria, donde aparentemente solapa ambas
definiciones y por eso espera un "access" donde no existe.

Creo que la mejor solución es crear ambos eventos en la misma clase, así no
dependés de estar alterando la carga de una clase y otra, aunque tampoco
hice la prueba para constatarlo.


Saludos!


El 2 de enero de 2015, 15:35, Juan R. Rossano <[email protected]>
escribió:

>  Gracias a todos. Conceptualmente estoy de acuerdo en que es mejor por
> norma definir los metodos en la clase que declara la propiedad. El problema
> se dio porque empezo a dar error un test unitario y de ahi empezamos a
> analizar que lo habia generado; entonces detectamos esta situación. Es
> mejor por norma que si hay un _access y un _assign se definan en la clase
> que declara la variable, pero en MSDN especifica que son metodos
> independientes y puede existir uno sin otro, no menciona ni controla que
> ese metodo no se defina en la subclase y funciona con esa definicion.
> Adjunto (y copio al pie por si no se puede descargar) dos PRG con el
> ejemplo que mencione (que no es el real sino uno creado para probar este
> caso); uno es EjemploMAL.prg y otro EjemploBIEN.prg que son simplemente el
> que da error y el que funciona bien, su unica diferencia es el orden de
> creacion de los objetos: primero persona y despues empleado no da error,
> primero empleado y despues persona si da error (lineas 5 y 6). Incluso
> ejecutando primero el que esta bien y despues el que esta mal funciona, a
> veces si primero se ejecuta el que esta mal y despues el que esta bien
> sigue dando error aun en el que esta bien.
> Mi deduccion por lo que investigue es que al crear un objeto persona se
> puede usar la funcion amembers() para acceder a la clase base y supongo
> (pero no pude encontrar ninguna referencia) que carga toda la estructura
> jerarquica de herencia. En el caso original nuestro devuelve 85 propiedades
> en la clase base y 89 en la implementada.  Y como el _access tiene
> prevalencia sobre la variable creo que deja la referencia y cuando se crea
> el segundo objeto (ahora de la clase base) ya detecta que esta cargada la
> estructura, no vuelve a cargarla y toma esa referencia a un _access que no
> existe, porque el error es que *no se encontro la propiedad
> variable_access*. Y eso si creo que es un Bug ya que no deberia funcionar
> dependiendo del orden de creacion de los objetos.
> Comparti el caso para confirmarlo porque no encontramos documentacion, es
> un caso de deduccion personal y toda opinion aporta. Creo que sirve como
> norma de codificacion ....
> Gracias a todos.
>
> *Juan*
>
> Ejemplo Bien
>
> local loEmp, loPer, lnCantidad
> dimension laPropiedades(1)
>
> *!*     Orden de creacion de objetos
> loPer = newobject(  'Persona' )
> loEmp = newobject( 'Empleado' )
> *!*     Fin de Orden de creacion de objetos
>
> ?loPer.Apellido
> lnCantidad = Amembers( laPropiedades,loPer,0,"UG+" )
> ?lnCantidad
>
> for i = 1 to lnCantidad
>     lcPropiedad = "loPer."+ alltrim( laPropiedades[i] )
>     if vartype( evaluate( lcPropiedad ) ) = "O"
>         if pemstatus(&lcPropiedad,"release",5)
>             lcEliminaReferencia = lcPropiedad + ".release"
>             &lcEliminaReferencia
>         endif
>     endif
> endfor
>
> loPer.Apellido = 'GOMEZ'
>
> ?loPer.Apellido
>
> loPer = null
>
> loEmp = newobject( 'Empleado' )
> ?loEmp.Apellido
> lnCantidad = Amembers( laPropiedades,loEmp,0,"UG+" )
> ?lnCantidad
>
> lnCantidad = Amembers( laPropiedades,'Persona',0,"UG+" )
> ?lnCantidad
>
> loEmp = null
>
> return
>
>
> define class Persona as Custom
>
>     Apellido = ''
>     Nombre = ''
>
>
> *-----------------------------------------------------------------------------------------
>     function Apellido_assign( tcVal as String) as Void
>         this.Apellido = tcVal
>     endfunc
>
>
> enddefine
>
> define class Empleado as Persona
>
>
>     documento = 0
>
>
> *-----------------------------------------------------------------------------------------
>     function Apellido_access() as String
>         return this.Apellido
>     endfunc
>
> enddefine
>
>
>
> Ejemplo Mal
>
> local loEmp, loPer, lnCantidad
> dimension laPropiedades(1)
>
> *!*     Orden de creacion de objetos
> loEmp = newobject( 'Empleado' )
> loPer = newobject(  'Persona' )
> *!*     Fin de Orden de creacion de objetos
>
> ?loPer.Apellido
> lnCantidad = Amembers( laPropiedades,loPer,0,"UG+" )
> ?lnCantidad
>
> for i = 1 to lnCantidad
>     lcPropiedad = "loPer."+ alltrim( laPropiedades[i] )
>     if vartype( evaluate( lcPropiedad ) ) = "O"
>         if pemstatus(&lcPropiedad,"release",5)
>             lcEliminaReferencia = lcPropiedad + ".release"
>             &lcEliminaReferencia
>         endif
>     endif
> endfor
>
> loPer.Apellido = 'GOMEZ'
>
> ?loPer.Apellido
>
> loPer = null
>
> loEmp = newobject( 'Empleado' )
> ?loEmp.Apellido
> lnCantidad = Amembers( laPropiedades,loEmp,0,"UG+" )
> ?lnCantidad
>
> lnCantidad = Amembers( laPropiedades,'Persona',0,"UG+" )
> ?lnCantidad
>
> loEmp = null
>
> return
>
>
> define class Persona as Custom
>
>     Apellido = ''
>     Nombre = ''
>
>
> *-----------------------------------------------------------------------------------------
>     function Apellido_assign( tcVal as String) as Void
>         this.Apellido = tcVal
>     endfunc
>
>
> enddefine
>
> define class Empleado as Persona
>
>
>     documento = 0
>
>
> *-----------------------------------------------------------------------------------------
>     function Apellido_access() as String
>         return this.Apellido
>     endfunc
>
> enddefine
>
>
>
> El 01/01/2015 11:25 p.m., César Pistiner escribió:
>
> Buenas noches Juan
>
> Yo estoy de acuerdo con Omar, acces y assign van juntos o simplemente usas
> uno u el otro, pero siempre dentro de la misma clase. De todas formas es
> interesante el comportamiento que mencionas de vfp. Si instancias una clase
> primero que la otra funcionan distinto? Eso si esta feo... Igual te repito
> nunca se me dio la necesidad de tener algo así, cuál es tu caso de uso?
>
> Saludos,
> César
>
> El jue, ene 1, 2015 04:04 PM, Fernando D. Bozzo <[email protected]>
> escribió:
>
>>  Omar tiene razón:
>>
>>  Access y Assign conviene crearlos juntos y simplemente son usados por
>> quienes lo necesiten.
>>
>>  Saludos.-
>>
>>
>>
>> El 1 de enero de 2015, 19:58, Omar Bellio <[email protected]>
>> escribió:
>>
>>   A ver si entendí bien:
>>>
>>> Cuando vos definís una clase con una propiedad, todo eso hereda hacia
>>> abajo, Empleado hereda de Persona, si vos ponés un método en Empleado,
>>> Persona no lo va a ver. Normalmente cuando pasa eso, se pone una interfaz
>>> (creo que se llama así) en la clase madre, es decir, definís el método y no
>>> le ponés código, queda abstracto para especializar en las subclases. De ese
>>> modo, el método siempre está, aunque no haga nada.
>>>
>>>
>>>
>>> Resumiendo para tu ejemplo: el método _Access tiene que estar en la
>>> clase madre, para que no te pase eso.
>>>
>>>
>>>
>>> Saludos.
>>>
>>>
>>>
>>> *De:* [email protected] [mailto:[email protected]] *En nombre de *Jose Paez
>>> *Enviado el:* miércoles, 31 de diciembre de 2014 07:59 p.m.
>>> *Para:* GUFA List Member
>>> *Asunto:* [GUFA] _Access y _Assign
>>>
>>>
>>>
>>> Hola Juan
>>>
>>>
>>>
>>> Yo he utilizado bastante estos métodos  en un framework que desarrolle
>>> hace mucho tiempo.
>>>
>>> Tendrás un ejemplo que puedas pasarnos (.prg o .vcx) para analizarlo.
>>>
>>>
>>>
>>> Saludos
>>>
>>>
>>>
>>> José Paez
>>>
>>>
>>>
>>>
>>>
>>> > Date: Wed, 31 Dec 2014 10:32:05 -0300
>>> > From: [email protected]
>>> > To: [email protected]
>>> > Subject: [GUFA] _Access y _Assign
>>> >
>>> > Descubrimos un problema con los metodos _Access y _Assign en herencia.
>>> > En una clase hay una propiedad y esta tiene definido el metodo
>>> _assign.
>>> > Otra clase hereda de esta y define para esa propiedad el metodo
>>> _access.
>>> > Pongo como ejemplo una clase Persona y otra Empleado que hereda de
>>> > Person. Se crea un objeto de cada clase. Si se crea primer la clase
>>> base
>>> > (persona) y despues la subclase (empleado) se puede acceder a la
>>> > propiedad de la primera (ejemplo Persona.Apellido). Si se crea primero
>>> > la subcase (empleado) y despues la base (persona) y se quiere acceder
>>> a
>>> > la propiedad que tiene el metodo _access en la subclase da error
>>> porque
>>> > no encuenta el metodo _access (al intentar Persona.Apellido da error
>>> > porque no encuentra apellido_access). Por lo que estuve investigando
>>> el
>>> > tema es que cuando crea un objeto levanta la estructura jerarquica de
>>> la
>>> > clase (a la que se puede acceder con la funcion amembers() consultando
>>> > por el objeto o cada clase en la jerarquia) y hace referencia a cada
>>> > propiedad si tiene algunos de los metodos (_access o _assign). No
>>> > encontre documentación que lo mencione, solo paso y lo confirme con un
>>> > pequeño ejemplo como el que describi (una clase persona con
>>> propiedades
>>> > apellido y nombre y una funcion apellido_assign y otra clase empleado
>>> > que hereda de persona con una propiedad mas cuil y el metodo
>>> > apellido_access). En la documentacion de microsoft menciona
>>> > explicitamente que se puede usar indistintamente _access o _assign,
>>> pero
>>> > nada habla de la herencia ¿alguien sabe algo de esto? Por lo que vimos
>>> > si se usa _access o _assign hay que crearlas en la misma definicion
>>> > donde esta la propiedad a menos que sea una clase abstracta y no se
>>> cree
>>> > ninguna instancia de la misma. No se si interesa pero para nosotros es
>>> > importante como norma de desarrollo.
>>> > Muchas gracias.
>>> >
>>> >
>>>
>>
>

Responder a