lunes, 23 de septiembre de 2013

Variables y Parámetros en C# - Parte 2

Tabla de Contenido

0. Introducción
1. ¿Qué es un Parámetro?
2. Pasar Argumentos por Valor
3. El Modificador ref
4. El Modificador out
5. Implicaciones al Pasar por Referencia
6. El Modificador params
7. Argumentos con Nombre
8. Conclusiones
9. Glosario
10. Referencias

0. Introducción

En esta ocasión, continuamos con los conceptos básicos de variable y parámetro. Le corresponde el turno a los parámetros. Éstas son las piezas de composición de los métodos, y los necesarios u opcionales, para que la tarea lógica del método se lleve a cabo según la implementación en particular.

1. ¿Qué es un Parámetro?

Su concepto más simple se traduce en la pieza fundamental para la construcción de los datos requeridos para llevar a cabo una tarea de la implementación de un método. Es decir, los valores o datos necesarios u opcionales requeridos para que el método pueda completar su tarea; los valores de los parámetros altera la secuencia, flujo, iteraciones, etc. que integran el método.


Como se mencionó, un método requiere de una parametrización (aunque hay que dejar claro que un método puede o no tener parámetros: por ejemplo, DarHora()). Los parámetros enlistados en un método definen el conjunto de argumentos que deben ser pasados a la hora de invocar un método. Veamos este ejemplo:

static void PruebaMetodo (int p)
{
p = p + 1; // Incremento en una unidad
Console.WriteLine(p); // Valor de p en la consola
}

static void Main ()
{
PruebaMetodo (8);
}

En este ejemplo, el método PruebaMetodo se ha especificado con un sólo argumento de tipo intp.

En puntos posteriores mostraré la manera cómo el programador puede controlar la forma en que se pasan los parámetros, a través de modificadores como ref  y out. En la Tabla 1 [1] se presentan algunas de las características fundamentales de estos modificadores, como son: la forma en que son pasados los parámetros (passed by), y el momento en qué deben ser asignadas las variables: antes o durante la llamada del método (variables must be definitely assigned).
Tabla 1. Modificadores de parámetros.png
Tabla 1. Modificadores de Parámetros.

2. Pasar Argumentos por Valor

En C#, por defecto los argumentos son pasados por valor a un método. Esto quiere decir que se asigna una copia del valor a la variable especificada en la lista de parámetros del método (como advirtió en la entrega anterior, esta copia se almacena en el stack asignado a la instancia del programa). En el ejemplo que viene ahora, se demuestra lo que sucede con los valores de las variables pasadas por valor:

Archivo C# PruebaMetodos.cs [enlace alternativo]:

La razón por la cual, el valor de x de la línea 8 no se ve alterado por lo cambios surtidos sobre p, se debe a que éstas variables se encuentran en diferentes locaciones de memoria [1].

Por otro lado, cuando se pasa un argumento de tipo por referencia, se crea una copia de la referencia, y no una copia del objeto. Esto es análogo a tener dos variables de tipo por referencia apuntando al mismo objeto a través de la referencia asignada en memoria para los datos del objeto. Aclaremos este concepto aún más con el ejemplo que viene a continuación:

Archivo C# PruebaArgumentoTipoReferencia.cs [enlace alternativo]:


En la declaración del método PruebaMetodoParametroReferencia el parámetro paramSb es una referencia al mismo objeto referenciado por sb  (línea 11); es decir que a pesar de que a paramSb se le haya asignado null (línea 6) la referencia original apunta aún a los datos agregados a la instancia. Cuando pasemos al tema de los modificadores, precisamente el modificador ref, la forma en que se tratan los parámetros de tipo por referencia varía sobremanera.

3. El Modificador ref

En el momento de especificar la lista de parámetros de un método, podemos recurrir al modificador ref para cambiar la forma en que se reciben los argumentos en la invocación de un método. En otras palabras, esta es una forma explícita de pasar un argumento por referencia en C#.

En la Referencia de C# [2] en MSDN dice:
The ref keyword causes an argument to be passed by reference, not by value.
En el siguiente ejemplo podemos ver esto con más claridad:

Archivo C# Pruebaref.cs [enlace alternativo]:

► Prueba de ejecución.

Ahora sucede lo contrario al caso cuando se pasa un argumento por valor, es decir, el parámetro del método también altera el valor de la variable que reside en el código del método que lo invoca. En el ejemplo anterior el valor de x (8) es modificado en la invocación al método PruebaModificadorRef (independiente del nombre de los identificadores).


En [1] se presenta una utilidad interesante e importante cuando se diseñen métodos de intercambio (swap, en inglés) [3]. Veamos este ejemplo práctico:

Archivo C# PruebaSwap.cs [enlace alternativo]:

► Prueba de ejecución.

A tener en cuenta [1]:
A parameter can be passed by reference or by value, regardless of whether the parameter type is a reference type or a value type.

4. El Modificador out

out [4] es un modificador que tiene características similares al ref, pero se diferencia en:
  • No es necesario que el argumento haya sido inicializado o que tenga asignado algún valor.
  • Antes de finalizar la ejecución de la función, es necesario haber asignado un valor a la variable de entrada.
¿Pero cuál es la utilidad de este modificador? Respuesta: cuando requiramos que un método nos retorne múltiples valores. Esto ocurre en el siguiente ejemplo:

Archivo C# Pruebaout.cs [enlace alternativo]:

► Prueba de ejecución.

5. Implicaciones al Pasar por Referencia

Cuando se trata de argumentos de tipo por referencia, las nuevas variables que se declaren y apunten al mismo objeto en realidad lo que ocurre detrás de cámara es la creación de un alias que identifica la ubicación actual en memoria de la variable existente [1].


En el código fuente de ejemplo, las variables x e y representan la misma instancia en memoria:

Archivo C# ImplicacionesArgumentosPorReferencia.cs [enlace alternativo]:
► Prueba de ejecución.

6. El Modificador params

Este modificador, params [5], permite la especificación de un número variable de parámetros. Un caso de ejemplo, puede ser el del método suma que permita sumar n cantidad de números pasados como argumento. Hay que aclarar que los parámetros de este tipo siempre van al final de la lista de parámetros de la firma del método, y que además, el tipo de datos de los argumentos debe ser un tipo en particular. Veamos el siguiente ejemplo:

Archivo C# Pruebaparams.cs [enlace alternativo]:
Observemos que el método Suma es invocado en las líneas 16 y 18 con un número diferente de argumentos: en la línea 16 con 5, y en la 18 con 3.

Debido a que un parámetro con el modificador params es un arreglo, también es posible hacer lo siguiente:

total = Suma (new int[] {11, 19, 29} );

► Prueba de ejecución.

7. Parámetros Opcionales

Los parámetros opcionales son aquellos que en su declaración es posible especificar un valor por defecto:

void Metodo( int x = 23 )
{
Console.WriteLine(x);
}

Ahora, en el momento de invocar el método Metodo:

Metodo(); // 23


el argumento puede ser omitido sin más. Básicamente lo que sudece detrás de todo esto, es que el valor entero 23 es pasado (asignado) al parámetro x. En [1]:
"...the compiler bakes the value 23 into the compiled code at the calling side."
Lo que básicamente nos dice es que el compilador, internamente representa la invocación sin argumento como:

Metodo(23);

A tener en cuenta [1]:
"Adding an optional parameters to a public method that's called from another assembly requires recompilation of both assemblies- just as though the parameter were mandatory."
Los parámetros opcionales no pueden ser marcados con los modificadores ref y out. Además, los parámetros obligatorios deben ser especificados antes que los opcionales tanto en la especificación de la firma del método como en la invocación del mismo. La excepción a la regla anterior es con argumentos variables -params- pues éstos siempre van al final de la lista de los argumentos.


Veamos esto ejemplo (nos da la oportunidad de entender un punto relacionado con el punto siguiente de este artículo):

void MetodoParametrosOpcionales (int x = 0, int y = 0)
{
Console.WriteLine( "Valor de x: " + x );
Console.WriteLine( "Valor de y: " + y );
}

El método de prueba:

void PruebaParametrosOpcionales()
{
MetodoParametrosOpcionales(1); // 1, 0
}

El valor 1 en MetodoParametrosOpcionales(1); es asignado a x, mientras que y es 0.


Y si quisiéramos hacer lo contrario. La respuesta la encontramos con el uso de los argumentos con nombre (named arguments, en inglés); el tema del siguiente punto de este artículo.

7. Argumentos con Nombre

Explícitamente, la utilidad de los argumentos con nombre es la posiblidad de identificar cada argumento de un método por su nombre; en lugar de su posición.

Pasemos a ver el siguiente ejemplo:

void MetodoPrueba (int x, int y)
{
Console.WriteLine( "Valor de x: " + x );
Console.WriteLine( "Valor de y: " + y );
}


Este método puede ser invocado con los nombres explícitos de los argumentos. Así:


void PruebaMetodoArgumentosConNombre()
{
MetodoPrueba(x:1, y:2); // 1, 2
}

La sintaxis para la invocación de un método haciendo uso de los argumentos con nombre consiste en nombrar el nombre del argumento y a continuación asignar el valor en cuestión, éstos dos anteriores separados por el signo de dos puntos seguidos (:). Esto nos da la posibilidad de invocar el método MetodoPrueba:

MetodoPrueba(x:1, y:2); // 1, 2
MetodoPrueba(y:2, x:1); // 1, 2

Los argumentos con nombre pueden ser combinados con los argumentos opcionales. Esto puede ser viable para:

MetodoPrueba(1, y:2); // 1, 2

Sin ambargo, existe una restricción respecto al uso de los parámetros opcionales: éstos deben ser especificados antes de los argumentos con nombre. En la siguiente instrucción se generaría un error:

MetodoPrueba(x:1, 2); // Error en tiempo de compilación

Otro ejemplo útil de combinar argumentos nombrados con parámetros opcionales, podría ser:

void Metodo (int a = 0, int b = 0, int c = 0, int d = 0)
{
// ...
}

Ahora podemos invocar el método anterior así:

Metodo(d:3);

8. Conclusiones

C# con una variedad de elementos de construcción de métodos, en especial el que tienen que ver con la firma o encabezado. Durante el artículo pudimos ver todas estas piezas con sus conceptos y varios ejemplos prácticos que demuestran su utilidad: cómo pasar argumentos (por valor y por referencia), los modificadores (ref: para pasar argumentos por referencia, out para pasar valores nulos y en la implementación del método asignar valores (obligatorio)). Consecuencias al pasar por referencia, en especial cuando tratamos con variablese de instancia. Y finalmente los argumentos con nombre combinados con parámetros opcionales: apropiados para cambiar el orden u omisión de los argumentos.

9. Glosario

- Argumentos con nombre
- Argumentos opcionales
- Modificador
- Swap (Intercambio)

1. Referencias

[1]: C# 5.0 in a Nutshell by Joseph Albahari and Ben Albahari. Copyright 2012 Joseph Albahari and Ben Albahari, 978-1-449-32010-2.
[2]: ref (C# Reference) - http://msdn.microsoft.com/en-us/library/14akc2c7.aspx
[3]: Swap (computer science) - Wikipedia, the free encyclopedia - http://en.wikipedia.org/wiki/Swap_(computer_science)
[4]: out parameter modifier (C# Reference) - http://msdn.microsoft.com/en-us/library/ee332485.aspx
[5]: params (C# Reference) - http://msdn.microsoft.com/en-us/library/w5zay9db.aspx
[6]: C# Optional Parameters - http://www.dotnetperls.com/optional-parameters
O

No hay comentarios:

Publicar un comentario

Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.