Índice de la sección dedicada a .NET (en el Guille) - Equivalencias VB / C#

Equivalencias entre Visual Basic y C# (3)

Publicado el 06/Ago/2006
Actualizado el 06/Ago/2006

Esta es la tercera página con equivalencias de las instrucciones entre los dos lenguajes más usados de .NET Framework: Visual Basic para .NET y C#. En las páginas anteriores (primera y segunda) puedes encontrar más equivalencias y algunas consideraciones que debes tener en cuenta a la hora de convertir código de Visual Basic a C# o viceversa.

 

Estas son las equivalencias publicadas en esta página:

  1. Select Case / switch
  2. Conversiones entre datos
  3. Sobre los redondeos de Visual Basic
  4. Parámetros opcionales (y sobrecargas)
  5. Array de parámetros opcionales
  6. Parámetros por valor y por referencia

1- Select Case / switch

Pues sí, esta se me pasó totalmente... por suerte hay gente que te recuerda las cosas, je, je.
En esta ocasión ha sido Eugenio Estrada, que aunque él ya lo ha publicado, pues... en fin... creo que es conveniente que estén todas en un mismo sitio para que resulte más fácil.
En realidad esta "equivalencia" debería estar en la primera página de equivalencias, pero como ha pasado ya mucho tiempo desde su publicación... pues... he preferido publicarla en una nueva, así te pongo algunas cosillas más.
Para "justificar" el retraso de más de tres años, te pongo algunas cosillas más que debes tener en cuenta sobre esta instrucción, que como podrás comprobar es mucho más potente en Visual Basic que en C#, aunque debemos ser precavidos a la hora de usar esa funcionalidad extra, tal como te comento más abajo.

Visual Basic C#
Select Case <condición>
    Case <opción 1>
        '...
    Case <opción 2>
        '...
    Case Else
        '...
End Select
switch (<condición>)
{
    case <opción 1>:
        //...
        break;
    case <opción 2>:
        //...
        break;
    default:
        //...
        break;
}
En C# los valores de las opciones case deben ser valores constantes, no se permiten expresiones ni variables, además de que solo se puede indicar un valor en cada "case", aunque se pueden indicar varios case para contemplar más de un valor para ejecutar el código de un mismo bloque.
En Visual Basic se permiten expresiones y para ello existen instrucciones que podemos indicar en cada bloque Case.
La condición, tanto en VB como en C#, puede ser una expresión.
Select Case <expresión con valor entero>
    Case 1
        '...
    Case 2, 3, 4
        '...
    Case Else
        '...
End Select

' También de esta forma
Select Case <expresión con valor entero>
    Case 1
        '...
    Case 2 To 4
        '...
    Case Else
        '...
End Select
switch (<expresión con valor entero>)
{
    case 1:
        //...
        break;
    case 2:
    case 3:
    case 4:
        //...
        break;
    default:
        //...
        break;
}
Además en Visual Basic se pueden usar varios valores en cada Case, separándolos con comas, y esos valores pueden ser expresiones de cualquier tipo, además de poder usarse variables, etc., es decir, cualquier cosa que produzca un valor del tipo esperado.
En Visual Basic, para indicar valores que requieran los operadores de comparación debemos usar Is, por ejemplo, para indicar que el valor sea mayor que 7, lo haremos con: Case Is > 7.
Y si queremos que esté dentro de un rango de valores, podemos usar To, en el ejemplo anterior hemos usado 2 To 4 para indicar los valores entre 2 y 4, pero también podemos combinar varias expresiones, por ejemplo:
Case 2 To 4, 9 To 12, Is > 99, Is < 299
En este caso se tendrían en cuenta todos los valores posibles indicados en esas expresiones. Como puedes comprobar, no podremos usar los operadores And, Or, etc., en su caso podemos usar varios Is.

ATENCIÓN:
Si usas Is < 299 debes tener en cuenta que esa condición se evalúa de forma independiente de las demás, por tanto el caso anterior, (si solo quieres valores hasta 299), lo puedes escribir solo con la última condición:
Case Is < 299
Ya que si no cumple ninguna de las anteriores, se evaluará esa, por tanto, si, por ejemplo, el valor de la condición indicada en Select Case fuese 8, también se evaluaría, ya que es menor de 299.

Pero el "problema" va a más y en el ejemplo Case 2 To 4, 9 To 12, Is > 99, Is < 299, en realidad "capturará" cualquier valor, ya que si se cumple el Is > 99 también se capturarán valores mayores de 298.
Por tanto, aunque en un Case puedas poner varias expresiones, debes ser consciente de que es lo que "realmente" estás haciendo... y no "pensar" que es lo que "supuestamente" estás haciendo.
 

Por último decir que como en Visual Basic los dos puntos se utilizan como separador de instrucciones en una misma línea, podemos usar los dos puntos para separar instrucciones Case, estén o no en la misma línea.
Case 2:
Case 3:

Case 2 : Case 3

Otra cosa a tener en cuenta (además de la advertencia anterior), es que cada sentencia Case solo se evaluará después de las que haya antes.
 

 


2- Conversiones entre datos

En Visual Basic para .NET podemos usar muchas formas de convertir datos de diferentes tipos, de hecho existen instrucciones propias para convertir entre tipos de datos "elementales", por ejemplo del tipo Double o String a Integer. Para convertir otros tipos de datos, existen ciertas instrucciones que nos permiten hacer esas conversiones, aunque solo funcionará si la conversión es posible, por ejemplo, si queremos convertir un tipo Cliente (definido por nosotros) en uno de tipo Empleado, esto solo será posible si hay alguna relación directa (por herencia o implementación de interfaces) entre esos dos tipos, o bien hemos definido alguna sobrecarga que permita hacer esa conversión (esto solo es posible en Visual Basic 2005 o superior).

Pero no nos complicaremos mucho, y solo veremos cómo convertir datos de diferentes tipos, y compararemos cómo sería el equivalente en C#. Ya que en C# no existen instrucciones propias para hacer las conversiones, por el contrario, todas las conversiones siempre se hacen de la misma forma.

Todo esto suponiendo que no estamos usando los métodos de la clase Convert, ya que en ese caso, las conversiones se hacen de la misma forma en ambos lenguajes.

Como ya he comentado, en Visual Basic usaremos instrucciones, cómo usar esas instrucciones, (y que parámetros permiten), tendrás que buscarlo en la ayuda de Visual Studio, ya que aquí solo te mostraré "la idea" de cómo usarlas.

Visual Basic C#
Convertir a tipo entero (Integer):
<resultado> = CInt(<expresión>)

<resultado> = CType(<expresión>, Integer)
 
<resultado> = (int)<expresión>
Convertir a tipo Double:
<resultado> = CDbl(<expresión>)

<resultado> = CType(<expresión>, Double)
 
<resultado> = (double)<expresión>

Aquí te muestro solo dos casos, pero para el resto sería lo mismo, las otras instrucciones de conversión son:
CBool, CByte, CChar, CDate, CDec, CLng, CObj, CSByte, CShort, CSng, CStr, CUInt, CULng, CUShort.
Algunas de estas, como CSByte y las tres últimas, solo están disponibles en Visual Basic 2005, ya que sirven para convertir a tipos que se definen por primera vez en esa versión de Visual Basic.
En todos los casos siempre puedes usar CType(<expresión>, <tipo>) para realizar la misma conversión.
Y como has visto en el código de C#, en ese lenguaje siempre se usa de la misma forma: (<tipo>)<expresión>, es decir, encerrando entre paréntesis el tipo y anteponiéndolo a la expresión a convertir.

En Visual Basic, además de CType, también podemos usar, (al menos para convertir expresiones a tipos por referencia), las instrucciones DirectCast y TryCast. Si sabemos que estamos trabajando con tipos por referencia estas últimas son preferibles a CType, ya que tienen mejor rendimiento.

DirectCast en realidad sirva para convertir cualquier tipo de datos, pero siempre que haya alguna relación de herencia o de implementación de interfaces.
TryCast, (que está disponible en Visual Basic 2005 y posterior), se usa solo con tipos por referencia, y se usa normalmente comprobando si el valor que devuelve no es nulo (Nothing).

En todas las conversiones, excepto con TryCast, si la conversión no se puede hacer, se produce una excepción del tipo InvalidCastException, con TryCast, si no se puede hacer la conversión "simplemente" se devuelve un valor nulo.

 

 

3- Sobre los redondeos de Visual Basic

Comprobando el código de números a letras que mi amigo Harvey Triana ha publicado en las colaboraciones, y después de proponerle unos cambios al código de Visual Basic, (el de C# no llegué a probarlo), me comentó que el código de C# funcionaba correctamente.
A pesar de las calores de este mes de Agosto, me entró curiosidad, y pude comprobar que el comportamiento de las conversiones a entero de C# y Visual Basic eran diferentes, y por tanto, no siempre producían el mismo valor, al menos usando las "instrucciones" equivalentes que te he comentado antes, en el caso de C# con (int) y en el de Visual Basic con CType(..., Integer).
Me puse a examinar un poco el código IL generado por las dos clases, y para mi extrañeza, (aunque en el fondo sabía que lo hacía, ya que las funciones de conversión a enteros de Visual Basic siempre redondean usando el llamado "redondeo bancario", tal como indica la documentación de Visual Studio), comprobé que Visual Basic añade una llamada a Math.Round que C# no utiliza; por tanto, si conviertes código de Visual Basic a C#, debes tener ese redondeo en cuenta, ya que C# no redondea cuando se hace el "cast" o conversión con (int), mientras que Visual Basic siempre lo hará, tanto con CType como con CInt.

Para que no haya comportamientos diferentes entre los dos lenguajes a la hora de hacer conversiones, (ni redondeos "no deseados o controlados"), puedes usar las funciones de conversión de la clase Convert, en el caso de convertir a un Integer (int en C#), tendrás que usar Convert.ToInt32.
Con las conversiones de la clase Convert siempre se usa el redondeo bancario, se use desde el lenguaje que se use.

 


4- Parámetros opcionales (y sobrecargas)

En Visual Basic, se pueden definir parámetros opcionales, usando la instrucción Optional, en C# no hay equivalencia para esa instrucción, por tanto no se pueden definir parámetros opcionales, al menos de la misma forma que en Visual Basic.

La única forma de definir parámetros opcionales en C# es usando un "array de parámetros", pero eso lo verás en la siguiente sección.

Si te interesa que tu código de Visual Basic pueda convertirse fácilmente a C#, deberías evitar el uso de parámetros opcionales con Optional. La solución es crear sobrecargas de los métodos que reciban esos parámetros opcionales, que a la larga es casi lo mismo y así no habrá conflictos entre los dos lenguajes.

Por ejemplo, si tienes este código de Visual Basic que usa Optional:

Public Shared Sub PruebaOptional(ByVal uno As Integer, _
                Optional ByVal dos As Integer = 0, _
                Optional ByVal tres As Boolean = True)
    '...
End Sub

Lo puedes convertir a este otro, en el que se usan sobrecargas para tener las tres posibilidades que nos da el código anterior:

Public Shared Sub PruebaOptional(ByVal uno As Integer)
    PruebaOptional(uno, 0, True)
End Sub

Public Shared Sub PruebaOptional(ByVal uno As Integer, _
                ByVal dos As Integer)
    PruebaOptional(uno, dos, True)
End Sub

Public Shared Sub PruebaOptional(ByVal uno As Integer, _
                ByVal dos As Integer, _
                ByVal tres As Boolean)
    '...
End Sub

Como ves, cuando definimos un parámetro con Optional, ese parámetro debe tener un valor predeterminado, que será el que se use cuando no se indique, y eso es lo que podemos hacer al definir las sobrecargas: llamamos al método que recibe todos los parámetros, pero usando los que debería tener si no se indican esos parámetros.

Si usamos parámetros opcionales, estos deben aparecer después de los que no son opcionales.

Lo que NO debes hacer es mezclar parámetros opcionales con sobrecargas, ya que en algunos casos el propio compilador te indicará que algo anda mal en ese código porque hay conflictos, ya que un parámetro Optional es opcional, pero también puede que se indique al llamar al método, por tanto, en algunos casos no será opcional, sino que se usará.

En C#, el código anterior de las sobrecargas, lo definiremos de esta forma:

public static void PruebaOptional(int uno) {
    PruebaOptional(uno, 0, true);
}

public static void PruebaOptional(int uno, int dos) {
    PruebaOptional(uno, dos, true);
}

public static void PruebaOptional(int uno, int dos, bool tres) {
    //...
}

 

La ventaja de Optional o de las sobrecargas, es que podemos usar parámetros de distintos tipos.

 


5- Array de parámetros opcionales

La alternativa de C# a los parámetros opcionales es usando un array de parámetros opcionales, esto mismo también se puede hacer con Visual Basic.

Para definir un método que reciba un array de parámetros opcionales, en Visual Basic usaremos la instrucción ParamArray, mientras que en C# usaremos params, en ambos casos, después de esa instrucción hay que indicar un array del tipo de datos que queramos usar internamente en el método.
En el siguiente código, los parámetros son de tipo entero y se devuelve la suma de todos ellos como un valor de tipo Long.

Public Shared Function PruebaArrayOpcional( ByVal ParamArray datos() As Integer) As Long
    Dim total As Long = 0
    For Each i As Integer In datos
        total += i
    Next
    Return total
End Function

 

public static long PruebaArrayOpcional(params int[] datos)
{
    long total = 0;
    foreach( int i in datos )
    {
        total += i;
    }
    return total;
}

En Visual Basic, podemos usar la instrucción ParamArray junto con Optional, es decir, podemos declarar parámetros Optional y parámetros con ParamArray, pero este último debe aparecer después de todos los Optional que tengamos.

Tanto en Visual Basic como en C#, el array de parámetros opcionales debe estar después de los parámetros que no son opcionales.

 


6- Parámetros por valor y por referencia

Y ya que estamos con el tema de los parámetros, veamos cómo definir los parámetros por valor y por referencia. Además de cómo usarlos.

Tanto en Visual Basic para .NET como en C#, de forma predeterminada, los parámetros son por valor, es decir, se pasa como argumento una copia del valor del parámetro. En Visual Basic, se puede usar la instrucción ByVal para indicar que el parámetro es por valor, de hecho, el propio IDE de Visual Basic siempre añade esa instrucción si no indicamos nada.

Cuando nos interese que podamos modificar el valor de un parámetro, por ejemplo para asignarle un nuevo valor, podemos usar los parámetros por referencia. En Visual Basic se indican con la instrucción ByRef, y en C#, se pueden indicar de dos formas, usando ref o bien usando out. La diferencia entre ref y out es que los argumentos pasados a parámetros ref deben estar previamente iniciados, es decir, deben tener algún valor; mientras que los parámetros out no es necesario que lo estén, y esa inicialización o asignación, hay que hacerla en el propio método.

Nota:
No debemos confundir los parámetros por referencia con los tipos por referencia, ya que un parámetro por referencia puede ser de un tipo por valor, como Integer o Double.
De hecho, cuando usamos tipos por referencia, no es necesario usar la instrucción ByRef para poder modificar el contenido de ese parámetro, ya que al ser un tipo por referencia, lo que se pasa es precisamente una referencia a la dirección de memoria en la que está dicho objeto, por tanto siempre tendremos acceso al contenido.

Debido a la forma que Visual Basic trata las declaraciones de las variables, en teoría no se podrían usar parámetros de tipo out, por tanto el equivalente más directo en C# es ref. Pero ambos parámetros se pueden "simular" en Visual Basic por medio de ByRef.

A la hora de usar los métodos con parámetros por referencia, la diferencia entre los dos lenguajes, es que en C# siempre tenemos que usar la instrucción out o ref que corresponda con la definición del parámetro, mientras que en Visual Basic no se debe usar la instrucción ByRef para usar un método que espere valores por referencia.

Veamos un método que recibe parámetros por valor y por referencia y cómo lo definiríamos en los dos lenguajes:

Public Shared Sub PruebaRef(ByRef uno As Integer, ByVal dos As Integer)
    ' Esta asignación afectará al parámetro
    uno += dos
    ' Esta no afectará al valor usado como segundo argumento
    dos = 999
End Sub

Public Shared Sub ProbandoRef()
    Dim uno As Integer = 5
    Dim dos As Integer = 2
    Console.WriteLine("uno= {0}, dos = {1}", uno, dos)
    PruebaRef(uno, dos)
    Console.WriteLine("uno= {0}, dos = {1}", uno, dos)
End Sub

 

public static void PruebaRef(ref int uno, int dos)
{
    // Esta asignación afectará al parámetro
    uno += dos;
    // Esta no afectará al valor usado como segundo argumento
    dos = 999;
}

public static void ProbandoRef()
{
    int uno = 5;
    int dos = 2;
    Console.WriteLine("uno= {0}, dos = {1}", uno, dos);
    PruebaRef(ref uno, dos);
    Console.WriteLine("uno= {0}, dos = {1}", uno, dos);
}

Como ves, en Visual Basic no hace falta indicar si el argumento se pasa a un parámetro por referencia o no, sin embargo en C# es obligatorio indicar si ese parámetro es ref, usando esa misma instrucción, si no lo hacemos, el compilador nos avisará que debemos hacerlo.

 

 


la Luna del Guille o... el Guille que está en la Luna... tanto monta...