none
crear variables en tiempo de ejecución

    Question

  • Hola.

    Tengo un txt con varias filas:

    variable1;200;2

    variable2;300;5

    .

    .

    variablen;n;n

     

    Luego lo que hago es con un for alamacenar en un array cada una de las filas, y luego cada una de ellas en otro array delimitado con split por ";"

     

    Ahora lo tengo así:

    var1(0) = variable1

    var1(1) = 200

    var1(2) = 2

     

    Lo que quiero saber es si puedo crear la varible "variable1" en tiempo de ejecución, leer del txt y crear una variable con ese nombre.

     

    Un saludo y gracias

    Monday, June 14, 2010 10:31 AM

Answers

  • "Fernando Gómez" escribió:

    > Al final, esto quiere decir que el OP puede usar ReDim cuando no tenga más
    > espacio y asignar el doble de elementos de los que tiene y alacanzar el
    > mismo efecto, pero pues si List<T> ya está construida, seguiría con la
    > opinión de que es mejor utilizar ésta sobre ReDim.

    Mira, sobre lo que es «mejor utilizar», no sabría que decirte, porque dependiendo de las circunstancias que se nos presenten, puede resultar útil utilizar una simple matriz, y en otras, puede que resulte mejor utilizar una colección genérica, o si lo prefieres, un objeto de la clase List(Of T).

    > ... Add se encarga de recalcular la capacidad de la lista y le
    > establece el valor 4 (no sé por qué ese en particular)

    Digo yo que será por el valor de la siguiente constante:

        Private Const _defaultCapacity As Integer = 4

    > Con respecto a List<T>... Interesante. Efectivamente ésta almacena los
    > objetos mediante una matriz y para cambiar el tamaño crea una nueva con el
    > nuevo tamaño y utiliza Array.Copy. Pero tiene la diferencia de que no
    > redimensiona cada vez que cambia de tamaño.
    >
    > La llamada a this.Capacity es la que se encarga de dimensionar el array
    > interno à la ReDim. Sin embargo, dado que List<T> hace un caché de
    > elementos, no tiene que redimensionar el array y copiar su contenido cada
    > vez que se inserta o elimina algo.

    Si vuelves a mirar la propiedad Capacity con Reflector, fíjate que en la asignación de la propiedad se ejecuta lo siguiente:


       If (value > 0) Then

          Dim destinationArray As T() = New T(value  - 1) {}

          If (Me._size > 0) Then
            Array.Copy(Me._items, 0, destinationArray, 0, Me._size)
          End If

          Me._items = destinationArray

       Else
          Me._items = List(Of T)._emptyArray

       End If

    Si el valor pasado es mayor que cero, se crea un nuevo objeto List(Of T) llamado «destinationArray», y SE COPIAN EN ÉL los elementos de la matriz correspondiente a la instancia actual de la clase. Una vez que el array de destino se ha copiado, se asigna al valor del campo llamado «_items», el cual tiene la siguiente declaración:

       Private _items As T()

    Es decir, el objeto List(Of T) interno que utiliza la clase, por tanto, podemos decir que al asignar el valor de la propiedad Capacity, se crea un nuevo objeto con la capacidad especificada, se copian en él los elementos actualmente existentes, y se asigna al objeto List(Of T) interno.

    Y volviendo a las matrices, te comento que no hay por qué redimensionar una matriz, y si se hace, es porque necesitamos que tenga más o menos elementos. Pero también puedo tener declarada una matriz con un número suficiente de elementos que actúe a modo de caché:

            ' Declaramos una matriz de 1000 elementos
            ' de números enteros:
            '
            Dim numeros (999) As Integer

    Si con ese número de elemento sé de antemano que va a ser suficiente, no necesito redimensionar la matriz. Pero si en un momento determinado me hacen falta más de 1000 números, entonces no tendré más remedio que redimensionarla, utilizando el modificador Preserve por si deseo que la nueva matriz respete los valores existentes en la matriz antigua. ¿Que no deseo respetar los valores existentes? Me olvido del modificador Preserve y solamente se creará una nueva matriz con el mismo rango, y se liberará automáticamente la matriz que ha sido reemplazada. Mas o menos a como actúa la propiedad Capacity del objeto List(Of T).

    Te insisto en que yo no tengo nada personal con la clase List(Of T), de hecho, hay circunstancias en las que la suelo a utilizar, pero tampoco creo que tengamos que "crucificar" a las matrices porque también suelen ser útiles en determinadas circunstancias, y no constituyen un "peligro social" ni nada por el estilo.

    Simplemente hay que saber cuando hay que utilizar una matriz o una lista genérica fuertemente tipificada. :-)


    Enrique Martínez [MS MVP - VB]
    Tuesday, June 15, 2010 10:54 AM
  • Hola:

    Si solamente vas a trabajar con tipos de datos primitivos (string, long, integer, etc.), te puede servir la clase CodePrimitiveExpression del espacio de nombres System.CodeDom.

    Por ejemplo, vamos a suponer que ya has leído tu archivo de texto y que has almacenado en el array «var1» el contenido de la primera fila, es decir, los valores

        variable1;200;2

    Crearías objetos CodePrimitiveExpression de la siguiente manera:

    Imports System.CodeDom

         Dim var1(2) As CodePrimitiveExpression

         ' Variable alfanumérica
         var1(0) = New CodePrimitiveExpression("variable1")

         ' Variables enteras
         var1(1) = New CodePrimitiveExpression(200)
         var1(2) = New CodePrimitiveExpression(2)


         ' Leemos los valores del array.
         '
         For Each var As CodePrimitiveExpression In var1

            MessageBox.Show(CStr(var.Value))

         Next

    Para pasar los valores del array de objetos CodePrimitiveExpression a variables normales y corrientes, lo harías así:

        Dim cadena As String = CStr(var1(0).Value)

        Dim entero1 As Integer = CInt(var1(1).Value)

        Dim entero2 As Integer = CInt(var1(2).Value)

    Es decir, la propiedad Value es la que te devuelve el valor real del objeto CodePrimitiveExpression que deberás de convertirlo al tipo de dato apropiado, ya que el valor que retorna es del tipo genérico Object.

    La verdad es que no se me ocurre el motivo que puedes tener para trabajar de ésta manera, pero tu verás lo que haces. :-)

    Para más información al respecto, te remito a la ayuda de Visual Studio:

    Referencia rápida de CodeDOM

    Un saludo

     


    Enrique Martínez [MS MVP - VB]
    Monday, June 14, 2010 1:44 PM
  • "Leonardo Tuttini" escribió:

    > en tu caso veo que usas un array, por ahi este sea algo duro de usar,
    > ya que no esta diseñado para que se redimenciona de una forma simple
    > cuando el contenido es variable

    No sé lo que será para tí "algo duro de usar". Pero como me dijistes una vez que habías trabajado con Visual Basic 6.0, deberías de saber que las matrices o arrays de Visual Basic .net, se encuentran perfectamente diseñadas para redimensionarlas dinámicamente de una forma simple, tal y como siempre se ha hecho con las matrices en Visual Basic.

    Aquí tienes un ejemplo:

            ' Declaramos un array de enteros sin ningún elemento
            Dim var() As Integer = Nothing

            ' Conforme recorremos un bucle lo dimensionamos
            ' dinámicamente y le asignamos valores a sus
            ' elementos.
            '
            For n As Integer = 0 To 9

                ReDim Preserve var(n)

                var(n) = n

            Next


            ' Comprobamos los valores del array
            For Each n As Integer In var
                MessageBox.Show(CStr(n))
            Next

    Lo mismo usar la instrucción «ReDim» es "algo duro de usar" para tí. ¡Ya me lo contarás! :-)

     

     


    Enrique Martínez [MS MVP - VB]
    Monday, June 14, 2010 1:58 PM

All replies

  • hola

    no puedes hacer esto, la definicion de las variables son fijas, no se crean en runtime, puedes si crear listas o colecciones de datos que seran alamacenadas en una variable

    en tu caso veo que usas un array, por ahi este sea algo duro de usar, ya que no esta diseñado para que se redimenciona de una forma simple cuando el contenido es variable

    pero hay colecciones mucho mas optimas por ejemplo el List(Of  ) o sea una lsita generica


    como veras este si permite agregar items de forma dinamica usando

    Dim lista As New List(Of String)
    lista.Add("variable1")
    lista.Add("200")
    lista.Add("2")

    y asi la cantida dde items que necesites

    hay otro tipo de colecciones aun mejores, como ser el Dictionary generico


    en este puedes definir una key para identificar los valores, por ahi en tu caso podrias usarlo para poner el la key, el nombre de la variable, lo bueno es que despeus puedes recuperar los valores por esa key

    Dim dicc As New Dictionary(Of String, List(Of String))

    veras que bueno puedes definir la clave como string y dentro una lista geenrica de string

    bueno espero que esto te sea de utilidad, investigalo un poco y realiza algunas pruebas seguro te ayuda

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Monday, June 14, 2010 12:09 PM
  • Hola:

    Si solamente vas a trabajar con tipos de datos primitivos (string, long, integer, etc.), te puede servir la clase CodePrimitiveExpression del espacio de nombres System.CodeDom.

    Por ejemplo, vamos a suponer que ya has leído tu archivo de texto y que has almacenado en el array «var1» el contenido de la primera fila, es decir, los valores

        variable1;200;2

    Crearías objetos CodePrimitiveExpression de la siguiente manera:

    Imports System.CodeDom

         Dim var1(2) As CodePrimitiveExpression

         ' Variable alfanumérica
         var1(0) = New CodePrimitiveExpression("variable1")

         ' Variables enteras
         var1(1) = New CodePrimitiveExpression(200)
         var1(2) = New CodePrimitiveExpression(2)


         ' Leemos los valores del array.
         '
         For Each var As CodePrimitiveExpression In var1

            MessageBox.Show(CStr(var.Value))

         Next

    Para pasar los valores del array de objetos CodePrimitiveExpression a variables normales y corrientes, lo harías así:

        Dim cadena As String = CStr(var1(0).Value)

        Dim entero1 As Integer = CInt(var1(1).Value)

        Dim entero2 As Integer = CInt(var1(2).Value)

    Es decir, la propiedad Value es la que te devuelve el valor real del objeto CodePrimitiveExpression que deberás de convertirlo al tipo de dato apropiado, ya que el valor que retorna es del tipo genérico Object.

    La verdad es que no se me ocurre el motivo que puedes tener para trabajar de ésta manera, pero tu verás lo que haces. :-)

    Para más información al respecto, te remito a la ayuda de Visual Studio:

    Referencia rápida de CodeDOM

    Un saludo

     


    Enrique Martínez [MS MVP - VB]
    Monday, June 14, 2010 1:44 PM
  • "Leonardo Tuttini" escribió:

    > en tu caso veo que usas un array, por ahi este sea algo duro de usar,
    > ya que no esta diseñado para que se redimenciona de una forma simple
    > cuando el contenido es variable

    No sé lo que será para tí "algo duro de usar". Pero como me dijistes una vez que habías trabajado con Visual Basic 6.0, deberías de saber que las matrices o arrays de Visual Basic .net, se encuentran perfectamente diseñadas para redimensionarlas dinámicamente de una forma simple, tal y como siempre se ha hecho con las matrices en Visual Basic.

    Aquí tienes un ejemplo:

            ' Declaramos un array de enteros sin ningún elemento
            Dim var() As Integer = Nothing

            ' Conforme recorremos un bucle lo dimensionamos
            ' dinámicamente y le asignamos valores a sus
            ' elementos.
            '
            For n As Integer = 0 To 9

                ReDim Preserve var(n)

                var(n) = n

            Next


            ' Comprobamos los valores del array
            For Each n As Integer In var
                MessageBox.Show(CStr(n))
            Next

    Lo mismo usar la instrucción «ReDim» es "algo duro de usar" para tí. ¡Ya me lo contarás! :-)

     

     


    Enrique Martínez [MS MVP - VB]
    Monday, June 14, 2010 1:58 PM
  • Hola,
     
    no sé si Leandro se refería a "difícil" o a "costoso en memoria" (aunque yo
    pienso que fue lo segundo dado lo que contestó inmediatamente).
     
    Según la documentación de MSDN sobre ReDim[1], ésta cláusula "libera la
    matriz existente y crea una matriz nueva con el mismo rango [siendo]
    reemplaza la matriz liberada en la variable de matriz [y] si se especifica
    el modificador Preserve, Visual Basic copia los elementos de la matriz
    existente en la nueva matriz". Por esto, creo que la utilización de ReDim es
    costosa, o por lo menos más costosa que utilizar alternativas como List(Of
    T). Personalmente, comparto la opinión de Leandro de que el OP debería usar
    List(Of T) o alguna colección similar si su matriz cambiará de tamaño muchas
    veces.
     
    Mis dos centavos... perdón por la interrupción :-)
     
    Saludos.
     
    [1] http://msdn.microsoft.com/es-es/library/w8k3cys2(VS.80).aspx
     
     


    Fernando Gómez
    fermasmas.wordpress.com
    Monday, June 14, 2010 4:39 PM
  • "Fernando Gómez" escribió:

    > Personalmente, comparto la opinión de Leandro de que el OP
    > debería usar List(Of T) o alguna colección similar si su
    > matriz cambiará de tamaño muchas veces.

    Hola, Fernando:

    No tengo nada en contra de utilizar la clase «List(Of T)». Pero ya que dices que Leandro se refería a "costoso en memoria", te diré que la clase «List(Of T)» implementa la interfaz «IList(Of T)» mediante una matriz o array que se redimensiona dinámicamente, por tanto y aplicando tu comentario, también sería "costoso en memoria", sobre todo si la lista cambia de tamaño con demasiado frecuencia.

    Lo que explica MSDN de la instrucción ReDim es sobre su comportamiento, no sobre si "cuesta o no demasiada memoria" o sobre si tiene un mayor o menor rendimiento en comparación con un objeto de la clase «List(Of T)» o alguna colección similar. :-)

    Un saludo


    Enrique Martínez [MS MVP - VB]
    Monday, June 14, 2010 4:56 PM
  • hola

    si en realdiad es un mix a donde apuntaba, si bien el tema de performance es importante tenerlo en cuenta, no vi que el planteo sea de un sistema en donde el rendimiento afecte demasiado

    mas que anda apunte a la naturalidad con que se usa la coleccion, un array require de metodos extra, como bien comento Enrique para poder redimencionar

    en cambio las listas o dictionary exponen su colecciones de items de una forma natural, usar el Add() es directo y se entiende que hace

    programe en VB6 y sabia lo del ReDim pero me parecio mas optimo proponer una solucion que involucre mas a VB.NET y no tanto a VB6, que vaya mas a lo moderlo en el uso de colecciones de datos

    es mas el dictionary para este caso iria genial porque podrias hacer

    List(Of String) listavar1 = dicc("variable1")

    y asi recuperas el contenido de esa variable directo por la key definida, no es una definicion stricta de tipos, pero se aproxima

    es mas existen metodo como Contains() para ver si existe la variable y proceder a usarla

    If dicc.Contains("variable1") Then

      'aqui se trabaja con el contenido de al variable 1

    End If

    muy natural nada forzado, en redimensionar o amplir la coleccion

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Monday, June 14, 2010 4:57 PM
  •  
     
    "SoftJaén" escribió en el mensaje de
    noticias:26db3de7-d7f2-4634-b28b-1b8f54d63364...
    > "Fernando Gómez" escribió:
    >
    >> Personalmente, comparto la opinión de Leandro de que el OP
    >> debería usar List(Of T) o alguna colección similar si su
    >> matriz cambiará de tamaño muchas veces.
    >
    > Hola, Fernando:
    >
    > No tengo nada en contra de utilizar la clase «List(Of T)». Pero ya que
    > dices que Leandro se refería a "costoso en memoria", te diré que la clase
    > «List(Of T)» implementa la interfaz «IList(Of T)» mediante una matriz o
    > array que se redimensiona dinámicamente, por tanto y aplicando tu
    > comentario, también sería "costoso en memoria", sobre todo si la lista
    > cambia de tamaño con demasiado frecuencia.
    >
     
    Hola de nuevo. Perdón, no me refería a costoso en memoria, sino a costoso en
    tiempo de proceso, mea culpa. Mmm, y yo no aseguro que Leandro se refería a
    costoso en memoria (o en procesamiento), es solo mi impresión.
     
    Con respecto a List<T>... Interesante. Efectivamente ésta almacena los
    objetos mediante una matriz y para cambiar el tamaño crea una nueva con el
    nuevo tamaño y utiliza Array.Copy. Pero tiene la diferencia de que no
    redimensiona cada vez que cambia de tamaño. Cuando creas un List<T> vacío
    sin especificar la capacidad inicial en el constructor, y luego agregas un
    elemento, Add se encarga de recalcular la capacidad de la lista y le
    establece el valor 4 (no sé por qué ese en particular) en la función privada
    EnsureCapacity (que se puede consultar con Reflector). Posteriormente, cada
    que List<T> necesita cambiar su tamaño, asigna el doble de los elementos
    actuales.
     
    // según Reflector en mscorlib para .NET 4
    private void EnsureCapacity(int min)
    {
    if (this._items.Length < min)
    {
    int num = (this._items.Length == 0) ? 4 : (this._items.Length * 2);
    if (num < min)
    {
    num = min;
    }
    this.Capacity = num;
    }
    }
     
    La llamada a this.Capacity es la que se encarga de dimensionar el array
    interno à la ReDim. Sin embargo, dado que List<T> hace un caché de
    elementos, no tiene que redimensionar el array y copiar su contenido cada
    vez que se inserta o elimina algo.
     
    Al final, esto quiere decir que el OP puede usar ReDim cuando no tenga más
    espacio y asignar el doble de elementos de los que tiene y alacanzar el
    mismo efecto, pero pues si List<T> ya está construida, seguiría con la
    opinión de que es mejor utilizar ésta sobre ReDim.
     
    Saludines.
     
     


    Fernando Gómez
    fermasmas.wordpress.com
    Monday, June 14, 2010 5:22 PM
  •  
    >
    > muy natural nada forzado, en redimensionar o amplir la coleccion
    >
     
    Eso de redimensionar me recuerdan los viejos arrays de C++ y la aritmética
    de punteros, las llamadas a calloc y realloc... Algo que me gusta de .NET es
    que trata a las colecciones como un objeto más y como tal toda la
    complejidad está oculta. Incluso C++ intentó hacer esto mismo con sus clases
    std::list, std::vector y demás de la librería estándar.
     
    En fin, no puedo negar que el debate ha estado bueno para comenzar una
    mañana de lunes... u.u
     
    :P
     
    Saludos.
     
     


    Fernando Gómez
    fermasmas.wordpress.com
    Monday, June 14, 2010 5:25 PM
  • "Fernando Gómez" escribió:

    > Al final, esto quiere decir que el OP puede usar ReDim cuando no tenga más
    > espacio y asignar el doble de elementos de los que tiene y alacanzar el
    > mismo efecto, pero pues si List<T> ya está construida, seguiría con la
    > opinión de que es mejor utilizar ésta sobre ReDim.

    Mira, sobre lo que es «mejor utilizar», no sabría que decirte, porque dependiendo de las circunstancias que se nos presenten, puede resultar útil utilizar una simple matriz, y en otras, puede que resulte mejor utilizar una colección genérica, o si lo prefieres, un objeto de la clase List(Of T).

    > ... Add se encarga de recalcular la capacidad de la lista y le
    > establece el valor 4 (no sé por qué ese en particular)

    Digo yo que será por el valor de la siguiente constante:

        Private Const _defaultCapacity As Integer = 4

    > Con respecto a List<T>... Interesante. Efectivamente ésta almacena los
    > objetos mediante una matriz y para cambiar el tamaño crea una nueva con el
    > nuevo tamaño y utiliza Array.Copy. Pero tiene la diferencia de que no
    > redimensiona cada vez que cambia de tamaño.
    >
    > La llamada a this.Capacity es la que se encarga de dimensionar el array
    > interno à la ReDim. Sin embargo, dado que List<T> hace un caché de
    > elementos, no tiene que redimensionar el array y copiar su contenido cada
    > vez que se inserta o elimina algo.

    Si vuelves a mirar la propiedad Capacity con Reflector, fíjate que en la asignación de la propiedad se ejecuta lo siguiente:


       If (value > 0) Then

          Dim destinationArray As T() = New T(value  - 1) {}

          If (Me._size > 0) Then
            Array.Copy(Me._items, 0, destinationArray, 0, Me._size)
          End If

          Me._items = destinationArray

       Else
          Me._items = List(Of T)._emptyArray

       End If

    Si el valor pasado es mayor que cero, se crea un nuevo objeto List(Of T) llamado «destinationArray», y SE COPIAN EN ÉL los elementos de la matriz correspondiente a la instancia actual de la clase. Una vez que el array de destino se ha copiado, se asigna al valor del campo llamado «_items», el cual tiene la siguiente declaración:

       Private _items As T()

    Es decir, el objeto List(Of T) interno que utiliza la clase, por tanto, podemos decir que al asignar el valor de la propiedad Capacity, se crea un nuevo objeto con la capacidad especificada, se copian en él los elementos actualmente existentes, y se asigna al objeto List(Of T) interno.

    Y volviendo a las matrices, te comento que no hay por qué redimensionar una matriz, y si se hace, es porque necesitamos que tenga más o menos elementos. Pero también puedo tener declarada una matriz con un número suficiente de elementos que actúe a modo de caché:

            ' Declaramos una matriz de 1000 elementos
            ' de números enteros:
            '
            Dim numeros (999) As Integer

    Si con ese número de elemento sé de antemano que va a ser suficiente, no necesito redimensionar la matriz. Pero si en un momento determinado me hacen falta más de 1000 números, entonces no tendré más remedio que redimensionarla, utilizando el modificador Preserve por si deseo que la nueva matriz respete los valores existentes en la matriz antigua. ¿Que no deseo respetar los valores existentes? Me olvido del modificador Preserve y solamente se creará una nueva matriz con el mismo rango, y se liberará automáticamente la matriz que ha sido reemplazada. Mas o menos a como actúa la propiedad Capacity del objeto List(Of T).

    Te insisto en que yo no tengo nada personal con la clase List(Of T), de hecho, hay circunstancias en las que la suelo a utilizar, pero tampoco creo que tengamos que "crucificar" a las matrices porque también suelen ser útiles en determinadas circunstancias, y no constituyen un "peligro social" ni nada por el estilo.

    Simplemente hay que saber cuando hay que utilizar una matriz o una lista genérica fuertemente tipificada. :-)


    Enrique Martínez [MS MVP - VB]
    Tuesday, June 15, 2010 10:54 AM