none
Error por cambio de valor de una propiedad

    Pregunta

  • Hola a todos:

    Me pasa una cosa muy curiosa, tengo una propiedad declarada como decimal en un array de (11) y bien, le asigno un valor a través de una fórmula y perfecto, lleva correctamente su valor por los sitios que pasa hasta que entra en una lista genérica y ahí ha perdido el valor del array (1 en adelante), solo tiene valor el 0.

    He usado un breakpoint y no he detectado nada raro, todo es correcto, por donde pasa lleva los valores correctamente.

     Entonces la pregunta ante este problema de no saber donde puede cambiar el valor de la propiedad, es, por si hay alguna forma de que pueda saber dónde puede estar cambiando ese valor ya que corriéndola está todo bien.

    Bueno esa es la pregunta y la duda o problema. He de comentar que entra en la lista con un messagebox antes de pasar por el try del principio, por ello que sea lista o no, no afecta para nada, ya que en ese messagebox ya ha perdido el valor y lo tiene como 0.

    Muchas gracias a todos.

    Gemma

    viernes, 4 de noviembre de 2016 19:37

Respuestas

  • "gemma_campillo" escribió:

    > Ahora te paso la declaración de la propiedad:
    > Private Shared _VentasAnalFinanc(11) As Decimal       
    > Public Shared Property VentasAnalFinanc() As Decimal()
    >        Get
    >            Return _VentasAnalFinanc
    >        End Get
    >        Set(ByVal value As Decimal())
    >            _VentasAnalFinanc = value
    >        End Set
    > End Property

    Efectivamente, es un procedimiento Property que lo tienes declarado como compartido ("jugar con fuego") en una Class, no en un Module.

    Te digo lo de "jugar con fuego" porque, a parte de estar compartido (Shared), en principio no estás teniendo en cuenta la advertencia de compilación nº 1819, que dice Las propiedades no deberían devolver matrices.

    Tal y como se recomienda en el artículo indicado, lo correcto sería que en lugar de un procedimiento Property implementaras un procedimiento Function para devolver el valor del campo _VentaAnalFinanc. Pero ¡claro! Si implementas un método, entonces no podrás asignarle un valor al citado campo desde fuera de la clase donde se encuentra declarado, ya que el campo está declarado como Private, por tanto, el bloque Get del procedimiento Property debería devolver una COPIA de la matriz:

        Public Shared Property VentasAnalFinanc() As Decimal()
            Get
                ' Devolver una copia de la matriz que contiene el campo
                Return DirectCast(_VentasAnalFinanc.Clone(), Decimal())
    
            End Get
            Set(ByVal value As Decimal())
                _VentasAnalFinanc = value
            End Set
        End Property

    No vas a perder nada por hacer una prueba declarando el bloque Get como indico, para ver si continuas o no teniendo el mismo problema con los valores del array.

    > Tengo centenares de ellas y todas funcionan correctamente.

    No sabes cuanto me alegro de que así sea. Pero hay que tener muchísimo cuidado cuando un procedimiento de propiedad devuelve una matriz, porque puedes estar modificando su valor sin darte cuenta, ya que las matrices son tipos de datos de referencia, de ahí que la advertencia 1819 advierta de que hay que mantener INVIOLABLE el valor del campo llamado _VentasAnalFinanc si no deseamos tener resultados inesperados.

    Puede que todo esto no tenga nada que ver con tu problema, pero yo no dormiría tranquilo observando el procedimiento Property que nos has mostrado. ;-)

    > Respecto a como entra el array en la lista genérica no tiene nada
    > que ver, ya que el messagebox lo pongo antes de entrar en la lista
    > genérica por lo que aún no ha hecho nada, ya que está antes del try, ...

    Que tú crees que no tiene nada que ver, y posiblemente así sea, pero la experiencia me dice que cuando tenemos resultados extraños, indudablemente algo estamos haciendo mal.

    >  Dim lst As New List(Of ActualizarTablaVarios_AnalEstadosFinancieros)

    Ahí estás creando una nueva lista genérica cuyos elementos serán del tipo ActualizarTablaVarios_AnalEstadosFinancieros.

    > lst.Add(New ActualizarTablaVarios_AnalEstadosFinancieros("360", VentasAnalFinanc(0),
    >    VentasAnalFinanc(1), VentasAnalFinanc(2), VentasAnalFinanc(3), VentasAnalFinanc(4),
    >    VentasAnalFinanc(5), VentasAnalFinanc(6), VentasAnalFinanc(7), VentasAnalFinanc(8), _
    >    VentasAnalFinanc(9), VentasAnalFinanc(10), VentasAnalFinanc(11), empresa))

    Y aquí estás añadiendo un nuevo elemento a la lista. Es decir, estás creando una nueva instancia de la clase ActualizarTablaVarios_AnalEstadosFinancieros pasándole a su constructor (procedimiento New) 14 parámetros. ¡No está mal!

    Ahora ya solo queda que nos muestres la clase ActualizarTablaVarios_AnalEstadosFinancieros para ver el código de su procedimiento New (el de los 14 parámetros) así como el de aquellos otros procedimientos que devuelven los valores de los campos de la clase, mayormente para observar si en alguna parte de la clase se está SOBRESCRIBIENDO los valores de la matriz que contiene el procedimiento de propiedad llamado VentasAnalFinanc.

    > Lo que intento y no se, es saber si hay alguna herramienta de vb.net
    > que permita ir viendo el valor que toma la propiedad cada vez que se
    > la llama.

    Para ello, lo más sencillo es establecer un punto de interrupción en el bloque Get para leer el valor que va a devolver el procedimiento Property:

    > Public Shared Property VentasAnalFinanc() As Decimal()
    >        Get
    >            Return _VentasAnalFinanc  --> Establece aquí un punto de interrupción.
    >        End Get


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.







    sábado, 5 de noviembre de 2016 9:26
    Moderador
  • "gemma_campillo" escribió:

    > En lo marcado en negrita: AccesoDatosFormulas.VentasAnalFinanc(i), en vez
    > de la (i), figuraba 1 y ese error provocaba que no saliese correctamente
    > el valor del array (1) y los siguientes.

    ¡Madre mía! ¡Desde luego para ...! Mejor no lo escribo. ;-)

    > For i As Integer = 0 To 11
    >     If dr.GetString(0) = "360" Then AccesoDatosFormulas.VentasAnalFinanc(i) = dr.GetDecimal(i + 1)
    > Next

    Te comento que esa NO ES LA MANERA IDÓNEA de asignar valores a una propiedad definida como una matriz, y me remito al artículo sobre la advertencia de compilación nº 1819 (Las propiedades no deberían devolver matrices).

    Como propiedad que es, tienes que asignarle una matriz del mismo tipo de dato, en éste caso Decimal, pero NO asignarle mediante un índice el valor a sus elementos.

    Lo correcto sería:

        ' Declarar una matriz temporal de 12 elementos. Te
        ' recuerdo que los índices están en base cero.
        '
        Dim temp(11) As Decimal
    
        For i As Integer = 0 To 11
            If (dr.GetString(0) = "360") Then
                ' Asignar los valores a la matriz temporal
                temp(i) = dr.GetDecimal(i + 1)
            End If
        Next
    
        ' Asignar el valor a la propiedad
        AccesoDatosFormulas.VentasAnalFinanc = temp


    Y la propiedad VentasAnalFinanc debería de devolver una copia del campo llamado _VentasAnalFinanc, y asignarle a éste también una copia del valor recibido:

        ' No dimensionar la matriz. Ésta tendrá los elementos
        ' que se le asignen a la propiedad.
        '
        Private Shared _VentasAnalFinanc() As Decimal
    
        Public Shared Property VentasAnalFinanc() As Decimal()
            Get
                Return DirectCast(_VentasAnalFinanc.Clone(), Decimal())
            End Get
            Set(ByVal value As Decimal())
                _VentasAnalFinanc = DirectCast(value.Clone, Decimal())
            End Set
        End Property

    Como tu lo haces, mejor sería que te olvidaras de una propiedad y definieras en la clase AccesoDatosFormulas un campo público y compartido:

    Public Shared VentasAnalFinanc(11) As Decimal

    Al menos, así es como yo lo entiendo, para que no se puedan modificar los elementos individuales del campo _VentasAnalFinanc mediante índices.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.





    sábado, 5 de noviembre de 2016 12:35
    Moderador
  • "gemma_campillo" escribió:

    > tengo una propiedad declarada como decimal en un array de (11) y bien, le
    > asigno un valor a través de una fórmula y perfecto, lleva correctamente su
    > valor por los sitios que pasa hasta que entra en una lista genérica y ahí
    > ha perdido el valor del array (1 en adelante), solo tiene valor el 0.

    Y, ¿cómo "entra el array" en la lista genérica?

    Se comprende que "VentasAnalFinanc" es una matriz o array. Pero, ¿dónde está el constructor (procedimiento New) de la lista genérica? ¿O cómo creas y añades los elementos a la lista genérica a la que te estás refiriendo?

    > VentasAnalFinanc es la propiedad.
    >

    ¿Propiedad? ¿A qué Class o Module pertenece esa propiedad? ¿O se trata de un CAMPO a nivel GLOBAL del proyecto que lo tienes declarado implícitamente como compartido (Shared) en algún Module de tu proyecto? Algo como:

         Module NombreModulo
    
             Public VentasAnalFinac() As Decimal
    
         End Module

    Si es así, tal declaración no tiene la consideración de propiedad (procedimiento Property), más bien la consideración de campo (Field).

    >    Select Case VarGlobal.StrCodPais 'Ventas Análisis estados financieros
    >        Case "34" 'España
    >            For i = 0 To valor
    >                VentasAnalFinanc(i) = (TotalVentas(i) + VariacExistenciasHaber(i) + TrabajosParaInmoviliz(i))
    >            Next
    >
    >        Case Else 'Colombia y otros paises
    >            For i = 0 To valor
    >                VentasAnalFinanc(i) = (TotalVentas(i) - OtrosIngresos(i))
    >            Next
    >    End Select

    Aprovecho la respuesta para indicarte que si esa es la instrucción Select Case que tienes implementada, la puedes sustituir por una simple instrucción If ... Else ... End If, por lo que solamente tienes que estar pendiente de un solo bucle For ... Next en lugar de dos bucles que recorren los mismos números de elementos:

            ' Ventas Análisis estados financieros
            '
            For i = 0 To valor
    
                If (VarGlobal.StrCodPais = "34") Then
                    ' España
                    VentasAnalFinanc(i) = (TotalVentas(i) + VariacExistenciasHaber(i) + TrabajosParaInmoviliz(i))
    
                Else
                    ' Colombia y otros países
                    VentasAnalFinanc(i) = (TotalVentas(i) - OtrosIngresos(i))
    
                End If
    
            Next


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.



    sábado, 5 de noviembre de 2016 7:57
    Moderador
  • "gemma_campillo" escribió:

    > Bueno esta es la clase para la lista.
    >
    > Public Class ActualizarTablaVarios_AnalFinancieroLargoPlazo
    >

    Si la clase ActualizarTablaVarios_AnalEstadosFinancieros (que es sobre la que yo te he preguntado) tiene la misma implementación que la clase ActualizarTablaVarios_AnalFinancieroLargoPlazo, no observo nada fuera de lo común para que se modifique el valor de la matriz devuelta por la propiedad VentasAnalFinanc, porque lo único que hacen los distintos procedimientos Property es devolver el valor de su campo relacionado, valores éstos que se los asignas a los campos en el constructor de la clase. Y el método ToString, lo único que hace es devolver un valor alfanumérico formateado para construir la sintaxis de una consulta SQL de actualización para actualizar la tabla Varios de tu base de datos.

    Desde luego, ahí no está el problema, aunque está claro que tienes un problema, porque los valores de los distintos elementos de una matriz no se modifican por "arte de magia".

    > Ah! Una cosa: El valor que le asigno a la propiedad, 'normalmente' proviene
    > de una consulta select y en ningún caso no hay ningún sitio donde ese valor
    > varíe. Es decir, siempre es el mismo valor inicial que se le asigna a la propiedad.

    No entiendo. Me dices que el valor que le asignas a la propiedad VentasAnalFinanc (que es una matriz de valores Decimal), proviene del resultado de ejecutar una consulta SELECT. Si es así, tampoco veo nada extraño en ello, siempre y cuando estés completamente segura que posteriormente no se modifican los valores de los elementos de la matriz en algún otro sitio.

    Para ver si se modifica o no, establece también un punto de interrupción en el bloque Set de la propiedad VentasAnalFinanc, para que el código se detenga cada vez que se le asigne un valor a dicha propiedad:

    Public Shared Property VentasAnalFinanc() As Decimal()
            Get
                ' Establece un punto de interrupción aquí para cuando
                ' se quiera LEER el valor de la propiedad.
                Return _VentasAnalFinanc 
            End Get
            Set(ByVal value As Decimal())
                ' Establece un punto de interrupción aquí para cuando
                ' se quiera ESTABLECER el valor de la propiedad.
                _VentasAnalFinanc = value
            End Set
    End Property

    Cuando el código se detenga en el bloque Set, lee el valor del parámetro values, y recorre el código pulsando la tecla F8 para ver desde dónde se ha llamado al bloque Set para establecer los valores de la propiedad.

    > Nota: Disculpas por no haberte contestado antes pero he tenido que salir.

    No te preocupes. Lo primero y más importante de todo, es salir a comprar el pan. ¡Jejejeje!


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.




    sábado, 5 de noviembre de 2016 11:41
    Moderador

Todas las respuestas

  • Coloca el código para que lo veamos

    Saludos

    viernes, 4 de noviembre de 2016 19:52
  • Hola:

    Este es el código que procede varias select. No tiene nada de particular.

    Public Shared Sub Formula_VentasAnalFinanc() Try Dim i As Integer Dim valor As Integer = AccesoLogica.ObtenerPeriodos() Select Case VarGlobal.StrCodPais 'Ventas Análisis estados financieros Case "34" 'España For i = 0 To valor

    VentasAnalFinanc(i) = (TotalVentas(i) + VariacExistenciasHaber(i) + TrabajosParaInmoviliz(i)) Next Case Else 'Colombia y otros paises For i = 0 To valor VentasAnalFinanc(i) = (TotalVentas(i) - OtrosIngresos(i)) Next End Select '//////////////////////////// 'Calculamos la media anual. Dim Wconvalor As Decimal Dim WSuma As Decimal WSuma = VentasAnalFinanc(0) + VentasAnalFinanc(1) + VentasAnalFinanc(2) + VentasAnalFinanc(3) + VentasAnalFinanc(4) + VentasAnalFinanc(5) _ + VentasAnalFinanc(6) + VentasAnalFinanc(7) + VentasAnalFinanc(8) + VentasAnalFinanc(9) + VentasAnalFinanc(10) + VentasAnalFinanc(11) For i = 0 To valor If VentasAnalFinanc(i) <> 0 Then Wconvalor = Wconvalor + 1 End If Next i 'Calculamos la media de los ejercicios If Wconvalor <> 0 Then MediaAnualdeVentasAnalFinanc = WSuma / Wconvalor End If Catch ex As Exception MessageBox.Show("Bloqueo en carga de Fórmula: '3124'" & vbCrLf & ex.Message & vbCrLf & "Acepte para continuar.", "FINANCIAL SYSTEM", MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End Sub

    VentasAnalFinanc es la propiedad.

    Un saludo y gracias.

    Gemma



    • Editado gemma_campillo viernes, 4 de noviembre de 2016 20:34 sintaxis
    viernes, 4 de noviembre de 2016 20:30
  • "gemma_campillo" escribió:

    > tengo una propiedad declarada como decimal en un array de (11) y bien, le
    > asigno un valor a través de una fórmula y perfecto, lleva correctamente su
    > valor por los sitios que pasa hasta que entra en una lista genérica y ahí
    > ha perdido el valor del array (1 en adelante), solo tiene valor el 0.

    Y, ¿cómo "entra el array" en la lista genérica?

    Se comprende que "VentasAnalFinanc" es una matriz o array. Pero, ¿dónde está el constructor (procedimiento New) de la lista genérica? ¿O cómo creas y añades los elementos a la lista genérica a la que te estás refiriendo?

    > VentasAnalFinanc es la propiedad.
    >

    ¿Propiedad? ¿A qué Class o Module pertenece esa propiedad? ¿O se trata de un CAMPO a nivel GLOBAL del proyecto que lo tienes declarado implícitamente como compartido (Shared) en algún Module de tu proyecto? Algo como:

         Module NombreModulo
    
             Public VentasAnalFinac() As Decimal
    
         End Module

    Si es así, tal declaración no tiene la consideración de propiedad (procedimiento Property), más bien la consideración de campo (Field).

    >    Select Case VarGlobal.StrCodPais 'Ventas Análisis estados financieros
    >        Case "34" 'España
    >            For i = 0 To valor
    >                VentasAnalFinanc(i) = (TotalVentas(i) + VariacExistenciasHaber(i) + TrabajosParaInmoviliz(i))
    >            Next
    >
    >        Case Else 'Colombia y otros paises
    >            For i = 0 To valor
    >                VentasAnalFinanc(i) = (TotalVentas(i) - OtrosIngresos(i))
    >            Next
    >    End Select

    Aprovecho la respuesta para indicarte que si esa es la instrucción Select Case que tienes implementada, la puedes sustituir por una simple instrucción If ... Else ... End If, por lo que solamente tienes que estar pendiente de un solo bucle For ... Next en lugar de dos bucles que recorren los mismos números de elementos:

            ' Ventas Análisis estados financieros
            '
            For i = 0 To valor
    
                If (VarGlobal.StrCodPais = "34") Then
                    ' España
                    VentasAnalFinanc(i) = (TotalVentas(i) + VariacExistenciasHaber(i) + TrabajosParaInmoviliz(i))
    
                Else
                    ' Colombia y otros países
                    VentasAnalFinanc(i) = (TotalVentas(i) - OtrosIngresos(i))
    
                End If
    
            Next


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.



    sábado, 5 de noviembre de 2016 7:57
    Moderador
  • Hola maestro, buenos días:

    Mira, ya he arreglado lo de la select, por un  if.

    Ahora te paso la declaración de la propiedad:

    Private Shared _VentasAnalFinanc(11) As Decimal        Public Shared Property VentasAnalFinanc() As Decimal() Get Return _VentasAnalFinanc End Get Set(ByVal value As Decimal()) _VentasAnalFinanc = value End Set End Property

    Tengo centenares de ellas y todas funcionan correctamente.

    Respecto a como entra el array en la lista genérica no tiene nada que ver, ya que el messagebox lo pongo antes de entrar en la lista genérica por lo que aún no ha hecho nada, ya que está antes del try, de cualquier forma te lo muestro pero el error no está ahí, tiene que estar en algún sitio que desconozco en el cual cambia de valor el array(1) y lo pone a 0, no tengo en ningún sitio ningún redim o alguna instrucción que diga que el valor(1) se tiene que poner a 0, solamente lleva correcto el valor de la propiedad con el array (0), o sea el primer valor si lo coge bien y no lo pierde, por eso digo que es muy raro, he pasado un breakpoint por todos los sitios en que aprece la propiedad y en todos es correcto.

     Public Shared Sub ListOF_AnalEstadosFinancieros_ActualizacionValoresTabla() 'Repasado
            MessageBox.Show("Valor (0)= " & VentasAnalFinanc(0)) 'Lleva su valor
            MessageBox.Show("Valor (1)= " & VentasAnalFinanc(1)) 'Aquí lleva el valor a 0.
    
            Try
                Dim lst As New List(Of ActualizarTablaVarios_AnalEstadosFinancieros)
                Dim empresa As String = VarGlobal.StrCodEmpresa
    
                If VarGlobal.StrCodPais = "34" Then
                    If VarGlobal.StrPlanConta = "PLAN 2007" OrElse VarGlobal.StrPlanConta = "FISCAL" Then
                        lst.Add(New ActualizarTablaVarios_AnalEstadosFinancieros("360", VentasAnalFinanc(0), VentasAnalFinanc(1), VentasAnalFinanc(2), VentasAnalFinanc(3), VentasAnalFinanc(4), VentasAnalFinanc(5), VentasAnalFinanc(6), VentasAnalFinanc(7), VentasAnalFinanc(8), VentasAnalFinanc(9), VentasAnalFinanc(10), VentasAnalFinanc(11), empresa))
    ...//...
    'Aquí van más elementos y todos llevan su valor correctamente.
    
    
     End If
    
    
    
    
                Using cnn As DbConnection = da.CreateConnection()
                    cnn.Open()
    
                    ' Creamos el Commando
                    Dim cmd As DbCommand = cnn.CreateCommand()
    
                    For Each item As ActualizarTablaVarios_AnalEstadosFinancieros In lst
    
                        cmd.CommandText = item.Update()
    
                        cmd.ExecuteNonQuery()
    
                    Next
                End Using
    
            Catch ex As Exception
                MessageBox.Show("Bloqueo en carga de Fórmula:     'ListasOF AnalEstadosFinanc.'" & vbCrLf & ex.Message & vbCrLf &
                       "Acepte para continuar.", "FINANCIAL SYSTEM", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub

    Lo que intento y no se, es saber si hay alguna herramienta de vb.net que permita ir viendo el valor que toma la propiedad cada vez que se la llama.

    Bueno, querido Enrique. De todas formas formas, he hecho un update normal y corriente y efectivamente funciona a la perfección, ahora si dejo que entre y no tildo el array en la lista, me lo vuelve a poner a 0, es decir, me cambia el valor del elemento 1 del array por 0. En algún sitio le pasa algo a esa propiedad y no se detectar donde.

    Bueno, muchas gracias como siempre querido amigo.,

    Un fuerte abrazo.

    Gemma


    • Editado gemma_campillo sábado, 5 de noviembre de 2016 8:34 sintaxis
    sábado, 5 de noviembre de 2016 8:31
  • "gemma_campillo" escribió:

    > Ahora te paso la declaración de la propiedad:
    > Private Shared _VentasAnalFinanc(11) As Decimal       
    > Public Shared Property VentasAnalFinanc() As Decimal()
    >        Get
    >            Return _VentasAnalFinanc
    >        End Get
    >        Set(ByVal value As Decimal())
    >            _VentasAnalFinanc = value
    >        End Set
    > End Property

    Efectivamente, es un procedimiento Property que lo tienes declarado como compartido ("jugar con fuego") en una Class, no en un Module.

    Te digo lo de "jugar con fuego" porque, a parte de estar compartido (Shared), en principio no estás teniendo en cuenta la advertencia de compilación nº 1819, que dice Las propiedades no deberían devolver matrices.

    Tal y como se recomienda en el artículo indicado, lo correcto sería que en lugar de un procedimiento Property implementaras un procedimiento Function para devolver el valor del campo _VentaAnalFinanc. Pero ¡claro! Si implementas un método, entonces no podrás asignarle un valor al citado campo desde fuera de la clase donde se encuentra declarado, ya que el campo está declarado como Private, por tanto, el bloque Get del procedimiento Property debería devolver una COPIA de la matriz:

        Public Shared Property VentasAnalFinanc() As Decimal()
            Get
                ' Devolver una copia de la matriz que contiene el campo
                Return DirectCast(_VentasAnalFinanc.Clone(), Decimal())
    
            End Get
            Set(ByVal value As Decimal())
                _VentasAnalFinanc = value
            End Set
        End Property

    No vas a perder nada por hacer una prueba declarando el bloque Get como indico, para ver si continuas o no teniendo el mismo problema con los valores del array.

    > Tengo centenares de ellas y todas funcionan correctamente.

    No sabes cuanto me alegro de que así sea. Pero hay que tener muchísimo cuidado cuando un procedimiento de propiedad devuelve una matriz, porque puedes estar modificando su valor sin darte cuenta, ya que las matrices son tipos de datos de referencia, de ahí que la advertencia 1819 advierta de que hay que mantener INVIOLABLE el valor del campo llamado _VentasAnalFinanc si no deseamos tener resultados inesperados.

    Puede que todo esto no tenga nada que ver con tu problema, pero yo no dormiría tranquilo observando el procedimiento Property que nos has mostrado. ;-)

    > Respecto a como entra el array en la lista genérica no tiene nada
    > que ver, ya que el messagebox lo pongo antes de entrar en la lista
    > genérica por lo que aún no ha hecho nada, ya que está antes del try, ...

    Que tú crees que no tiene nada que ver, y posiblemente así sea, pero la experiencia me dice que cuando tenemos resultados extraños, indudablemente algo estamos haciendo mal.

    >  Dim lst As New List(Of ActualizarTablaVarios_AnalEstadosFinancieros)

    Ahí estás creando una nueva lista genérica cuyos elementos serán del tipo ActualizarTablaVarios_AnalEstadosFinancieros.

    > lst.Add(New ActualizarTablaVarios_AnalEstadosFinancieros("360", VentasAnalFinanc(0),
    >    VentasAnalFinanc(1), VentasAnalFinanc(2), VentasAnalFinanc(3), VentasAnalFinanc(4),
    >    VentasAnalFinanc(5), VentasAnalFinanc(6), VentasAnalFinanc(7), VentasAnalFinanc(8), _
    >    VentasAnalFinanc(9), VentasAnalFinanc(10), VentasAnalFinanc(11), empresa))

    Y aquí estás añadiendo un nuevo elemento a la lista. Es decir, estás creando una nueva instancia de la clase ActualizarTablaVarios_AnalEstadosFinancieros pasándole a su constructor (procedimiento New) 14 parámetros. ¡No está mal!

    Ahora ya solo queda que nos muestres la clase ActualizarTablaVarios_AnalEstadosFinancieros para ver el código de su procedimiento New (el de los 14 parámetros) así como el de aquellos otros procedimientos que devuelven los valores de los campos de la clase, mayormente para observar si en alguna parte de la clase se está SOBRESCRIBIENDO los valores de la matriz que contiene el procedimiento de propiedad llamado VentasAnalFinanc.

    > Lo que intento y no se, es saber si hay alguna herramienta de vb.net
    > que permita ir viendo el valor que toma la propiedad cada vez que se
    > la llama.

    Para ello, lo más sencillo es establecer un punto de interrupción en el bloque Get para leer el valor que va a devolver el procedimiento Property:

    > Public Shared Property VentasAnalFinanc() As Decimal()
    >        Get
    >            Return _VentasAnalFinanc  --> Establece aquí un punto de interrupción.
    >        End Get


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.







    sábado, 5 de noviembre de 2016 9:26
    Moderador
  • Hola maestro:

    Menuda clase me has dado hoy, por Dios.

    Bueno esta es la clase para la lista.

    Imports System.Data.Common
    Imports System.Drawing
    
    Public Class ActualizarTablaVarios_AnalFinancieroLargoPlazo
        Private m_ejer1 As Decimal
        Private m_ejer2 As Decimal
        Private m_ejer3 As Decimal
        Private m_ejer4 As Decimal
        Private m_ejer5 As Decimal
        Private m_ejer6 As Decimal
        Private m_ejer7 As Decimal
        Private m_ejer8 As Decimal
        Private m_ejer9 As Decimal
        Private m_ejer10 As Decimal
        Private m_ejer11 As Decimal
        Private m_ejer12 As Decimal
        Private m_empresa As String
        Private m_orden As String
    
    
    
        Public Sub New(orden As String, ejer1 As Decimal, ejer2 As Decimal, ejer3 As Decimal, ejer4 As Decimal, ejer5 As Decimal, ejer6 As Decimal, ejer7 As Decimal, ejer8 As Decimal, ejer9 As Decimal, ejer10 As Decimal, ejer11 As Decimal, ejer12 As Decimal, empresa As String)
    
            m_orden = orden
            m_ejer1 = ejer1
            m_ejer2 = ejer2
            m_ejer3 = ejer3
            m_ejer4 = ejer4
            m_ejer5 = ejer5
            m_ejer6 = ejer6
            m_ejer7 = ejer7
            m_ejer8 = ejer8
            m_ejer9 = ejer9
            m_ejer10 = ejer10
            m_ejer11 = ejer11
            m_ejer12 = ejer12
            m_empresa = empresa
    
        End Sub
    
        Public ReadOnly Property ejer1 As Decimal
            Get
                Return m_ejer1
            End Get
        End Property
    
        Public ReadOnly Property ejer2 As Decimal
            Get
                Return m_ejer2
            End Get
        End Property
    
        Public ReadOnly Property ejer3 As Decimal
            Get
                Return m_ejer3
            End Get
        End Property
    
        Public ReadOnly Property ejer4 As Decimal
            Get
                Return m_ejer4
            End Get
        End Property
    
        Public ReadOnly Property ejer5 As Decimal
            Get
                Return m_ejer5
            End Get
        End Property
    
        Public ReadOnly Property ejer6 As Decimal
            Get
                Return m_ejer6
            End Get
        End Property
    
        Public ReadOnly Property ejer7 As Decimal
            Get
                Return m_ejer7
            End Get
        End Property
    
        Public ReadOnly Property ejer8 As Decimal
            Get
                Return m_ejer8
            End Get
        End Property
    
        Public ReadOnly Property ejer9 As Decimal
            Get
                Return m_ejer9
            End Get
        End Property
    
        Public ReadOnly Property ejer10 As Decimal
            Get
                Return m_ejer10
            End Get
        End Property
    
        Public ReadOnly Property ejer11 As Decimal
            Get
                Return m_ejer11
            End Get
        End Property
    
        Public ReadOnly Property ejer12 As Decimal
            Get
                Return m_ejer12
            End Get
        End Property
    
        Public ReadOnly Property empresa As String
            Get
                Return m_empresa
            End Get
        End Property
    
        Public ReadOnly Property orden As String
            Get
                Return m_orden
            End Get
        End Property
    
    
        Public Function Update() As String
    
            Return String.Format("UPDATE Varios Set Ejer_01={0}, Ejer_02={1}, Ejer_03={2}, Ejer_04={3}, Ejer_05={4}, Ejer_06={5}, Ejer_07={6}, Ejer_08={7}, Ejer_09={8}, Ejer_10={9}, Ejer_11={10}, Ejer_12={11} WHERE Cod_Empresa='{12}' AND Orden='{13}'",
                                 m_ejer1.ToString().Replace(",", "."), m_ejer2.ToString().Replace(",", "."), m_ejer3.ToString().Replace(",", "."), m_ejer4.ToString().Replace(",", "."), m_ejer5.ToString().Replace(",", "."), m_ejer6.ToString().Replace(",", "."),
                                m_ejer7.ToString().Replace(",", "."), m_ejer8.ToString().Replace(",", "."), m_ejer9.ToString().Replace(",", "."), m_ejer10.ToString().Replace(",", "."), m_ejer11.ToString().Replace(",", "."), m_ejer12.ToString().Replace(",", "."), m_empresa, m_orden)
    
        End Function
    End Class

    Ahora según lo que me indiques, voy a cambiar cosas que creo importantes en todo lo que me has explicado.

    Yo no se como leches sabes esas cosas.

    Ah! Una cosa: El valor que le asigno a la propiedad, 'normalmente' proviene de una consulta select y en ningún caso no hay ningún sitio donde ese valor varíe. Es decir, siempre es el mismo valor inicial que se le asigna a la propiedad.

    Bueno, como siempre muchas gracias querido amigo.

    Un abrazo.

    Gemma

    Nota: Disculpas por no haberte contestado antes pero he tenido que salir.


    sábado, 5 de noviembre de 2016 11:16
  • "gemma_campillo" escribió:

    > Bueno esta es la clase para la lista.
    >
    > Public Class ActualizarTablaVarios_AnalFinancieroLargoPlazo
    >

    Si la clase ActualizarTablaVarios_AnalEstadosFinancieros (que es sobre la que yo te he preguntado) tiene la misma implementación que la clase ActualizarTablaVarios_AnalFinancieroLargoPlazo, no observo nada fuera de lo común para que se modifique el valor de la matriz devuelta por la propiedad VentasAnalFinanc, porque lo único que hacen los distintos procedimientos Property es devolver el valor de su campo relacionado, valores éstos que se los asignas a los campos en el constructor de la clase. Y el método ToString, lo único que hace es devolver un valor alfanumérico formateado para construir la sintaxis de una consulta SQL de actualización para actualizar la tabla Varios de tu base de datos.

    Desde luego, ahí no está el problema, aunque está claro que tienes un problema, porque los valores de los distintos elementos de una matriz no se modifican por "arte de magia".

    > Ah! Una cosa: El valor que le asigno a la propiedad, 'normalmente' proviene
    > de una consulta select y en ningún caso no hay ningún sitio donde ese valor
    > varíe. Es decir, siempre es el mismo valor inicial que se le asigna a la propiedad.

    No entiendo. Me dices que el valor que le asignas a la propiedad VentasAnalFinanc (que es una matriz de valores Decimal), proviene del resultado de ejecutar una consulta SELECT. Si es así, tampoco veo nada extraño en ello, siempre y cuando estés completamente segura que posteriormente no se modifican los valores de los elementos de la matriz en algún otro sitio.

    Para ver si se modifica o no, establece también un punto de interrupción en el bloque Set de la propiedad VentasAnalFinanc, para que el código se detenga cada vez que se le asigne un valor a dicha propiedad:

    Public Shared Property VentasAnalFinanc() As Decimal()
            Get
                ' Establece un punto de interrupción aquí para cuando
                ' se quiera LEER el valor de la propiedad.
                Return _VentasAnalFinanc 
            End Get
            Set(ByVal value As Decimal())
                ' Establece un punto de interrupción aquí para cuando
                ' se quiera ESTABLECER el valor de la propiedad.
                _VentasAnalFinanc = value
            End Set
    End Property

    Cuando el código se detenga en el bloque Set, lee el valor del parámetro values, y recorre el código pulsando la tecla F8 para ver desde dónde se ha llamado al bloque Set para establecer los valores de la propiedad.

    > Nota: Disculpas por no haberte contestado antes pero he tenido que salir.

    No te preocupes. Lo primero y más importante de todo, es salir a comprar el pan. ¡Jejejeje!


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.




    sábado, 5 de noviembre de 2016 11:41
    Moderador
  • Hola maestro:

    Ya está solucionado. Me ha ido perfecto conocer los puntos de interrupción en Get y Set de la propiedad.

    El error estaba en el siguiente código en el cual muestro el valor de la propiedad:

      Public Shared Sub MostramosVentasAnalisisFinanciero()
            ' Creamos el acceso a datos mediante el nombre de la cadena de conexión existente en el archivo de configuración de la aplicación.
            Dim da As DataAccessInvariant = DataAccessInvariant.GetDataAccessInvariant(Configuracion.CadenaConexion)
    
            ' Declaramos una variable Connection
            Using cnn As DbConnection = da.CreateConnection()
    
                ' Creamos el Commando
                Dim cmd As DbCommand = cnn.CreateCommand()
    
                cnn.Open()
    
                cmd.CommandText = "SELECT Orden, Ejer_01, Ejer_02, Ejer_03, Ejer_04, Ejer_05, Ejer_06, Ejer_07, Ejer_08, Ejer_09, Ejer_10, Ejer_11, Ejer_12 " &
                                  "FROM Varios WHERE Cod_Empresa = @empresa AND Orden = '360'"
    
                cmd.Parameters.Add(Configuracion.CreateParameter(cmd, "@empresa", VarGlobal.StrCodEmpresa))
    
                Using dr As DbDataReader = cmd.ExecuteReader()
                    While dr.Read
                        For i As Integer = 0 To 11
                            If dr.GetString(0) = "360" Then AccesoDatosFormulas.VentasAnalFinanc(i) = dr.GetDecimal(i + 1)
                        Next
                    End While
                End Using
    
            End Using
        End Sub

    En lo marcado en negrita: AccesoDatosFormulas.VentasAnalFinanc(i), en vez de la (i), figuraba 1 y ese error provocaba que no saliese correctamente el valor del array (1) y los siguientes. Eso también me lo ha hecho ver que fallaba cuando eran 5 ejercicios, o sea, valor =4. ya que en los períodos mensuales (11) no fallaba. Ahí estaba el error y es ahí donde le cambiaba el valor a la propiedad.

    Bueno, voy a poner en marcha lo que me has comentado, pero para mi encuentro super práctico lo de saber los valores que llevan las propiedades Get y Set ya que creo que es muy importante para ver la luz en casos como este que me ha llevado horas averiguarlo.

    Maestro, mi querido maestro muchas gracias por tu explicaciones tan sumamente didácticas como siempre. Cada día de esa forma una aprende mucho más.

    Gracias Enrique y un fuerte abrazo como siempre. Cuídate mucho.

    Gemma

    sábado, 5 de noviembre de 2016 12:13
  • "gemma_campillo" escribió:

    > En lo marcado en negrita: AccesoDatosFormulas.VentasAnalFinanc(i), en vez
    > de la (i), figuraba 1 y ese error provocaba que no saliese correctamente
    > el valor del array (1) y los siguientes.

    ¡Madre mía! ¡Desde luego para ...! Mejor no lo escribo. ;-)

    > For i As Integer = 0 To 11
    >     If dr.GetString(0) = "360" Then AccesoDatosFormulas.VentasAnalFinanc(i) = dr.GetDecimal(i + 1)
    > Next

    Te comento que esa NO ES LA MANERA IDÓNEA de asignar valores a una propiedad definida como una matriz, y me remito al artículo sobre la advertencia de compilación nº 1819 (Las propiedades no deberían devolver matrices).

    Como propiedad que es, tienes que asignarle una matriz del mismo tipo de dato, en éste caso Decimal, pero NO asignarle mediante un índice el valor a sus elementos.

    Lo correcto sería:

        ' Declarar una matriz temporal de 12 elementos. Te
        ' recuerdo que los índices están en base cero.
        '
        Dim temp(11) As Decimal
    
        For i As Integer = 0 To 11
            If (dr.GetString(0) = "360") Then
                ' Asignar los valores a la matriz temporal
                temp(i) = dr.GetDecimal(i + 1)
            End If
        Next
    
        ' Asignar el valor a la propiedad
        AccesoDatosFormulas.VentasAnalFinanc = temp


    Y la propiedad VentasAnalFinanc debería de devolver una copia del campo llamado _VentasAnalFinanc, y asignarle a éste también una copia del valor recibido:

        ' No dimensionar la matriz. Ésta tendrá los elementos
        ' que se le asignen a la propiedad.
        '
        Private Shared _VentasAnalFinanc() As Decimal
    
        Public Shared Property VentasAnalFinanc() As Decimal()
            Get
                Return DirectCast(_VentasAnalFinanc.Clone(), Decimal())
            End Get
            Set(ByVal value As Decimal())
                _VentasAnalFinanc = DirectCast(value.Clone, Decimal())
            End Set
        End Property

    Como tu lo haces, mejor sería que te olvidaras de una propiedad y definieras en la clase AccesoDatosFormulas un campo público y compartido:

    Public Shared VentasAnalFinanc(11) As Decimal

    Al menos, así es como yo lo entiendo, para que no se puedan modificar los elementos individuales del campo _VentasAnalFinanc mediante índices.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.





    sábado, 5 de noviembre de 2016 12:35
    Moderador
  • Hola Enrique;

    Como siempre llevas razón y es un error mío que afecta a ese código que te he puesto y a otro, que por error se vuelve a asignar valor a la propiedad cuando no se tendría que haber hecho. Está corregido y ahora está hecho correctamente, solo se asigna valor una vez como resultado de la select que lo produce.

    Hay muchas selects y alguna cosilla o gazapo a veces puede colarse, pero estate tranquilo que está correcto todo lo que en asignaciones a la propiedad se refiere.

    Muchas gracias por hacérmelo notar, porque no había reparado en ello, me ha servido para corregir esta y otra que tenía.

    Gracias maestro por todo.

    Un fuerte abrazo.

    Gemma

    sábado, 5 de noviembre de 2016 15:09