Hola Juan!

Muchas gracias por el aporte, yo también creo que es un *bug*, aunque te
repito no se me ocurre un caso de uso.
Si lo que buscas es código seguro entre desarrolladores se me ocurre que
podes dejar el access y assign en la clase *Persona,* pero lanzar una
excepción en el access y hacer la verdadera implementación en el access de
la clase *Empleado*. ¿Se entiende? Con esto te cubrís de que si algún
desarrollador quiere obtener esa propiedad desde *Persona* le va a informar
que no puede, con esto más el uso de pruebas unitarias estarías cubierto [?]

Saludos,
César

PD: Me alegro que uses pruebas unitarias!!


El 2 de enero de 2015, 12:38, Fernando D. Bozzo <[email protected]>
escribió:

> 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