sábado, 20 de mayo de 2017

Curso de C#: métodos

Métodos


Los métodos son bloques de código manejan los datos de la clase. Cómo se define un método en C#:

acceso tipo NombreMetodo(TipoArg1 argumento1, TipoArg2 argumento2 ...)
{
    // Aquí se codifica lo que tiene que hacer el método
}

acceso es el modificador de acceso del método, que puede ser private, protected, internal o public (como las variables). Posteriormente el tipo de retorno, es decir, el tipo de dato que devolverá el método (que puede ser cualquier tipo). Luego el nombre del método (sin espacios en blanco). Después, entre paréntesis y separados unos de otros por comas, la lista de argumentos que aceptará el método: cada uno de ellos se especificará poniendo primero el tipo y después el nombre del mismo. Por fin, la llave de apertura de bloque seguida del código del método y, para terminarlo, la llave de cierre del bloque.


Curso de C#: métodos




Un método es como un procedimiento o una función. Necesitamos pasar datos a los métodos. Estos datos se llaman argumentos. Vamos a verlo:


    public bool MiMetodo(byte argumento)
    {
    }

Los métodos también pueden devolver un valor de cualquier tipo después de su ejecución si fuera necesario. En caso de que no devuelva nada hay que declararlo como void. 

Ejemplo. Escribir una clase que maneja gastos e ingresos:

class Cuentas
{
    protected double saldo=0;
    public double Saldo
    {
        get
        {
            return this.saldo;
        }
    }
      
    public bool NuevoGasto(double cantidad)
    {
        if (cantidad<=0) return false;

        this.saldo -= cantidad;
        return true;
    }

    public bool NuevoIngreso(double cantidad)
    {
        if (cantidad <=0) return false;

        this.saldo += cantidad;
        return true;
    }
}

Esta clase contiene una variable protected (es decir, que es visible dentro de la clase y dentro de clases derivadas, pero no desde el cliente), una propiedad y dos métodos. Los métodos NuevoIngreso y NuevoGasto se ocupan de modificar el valor de la variable saldo según cuánto se ingrese o se gaste. Si la cantidad que se pretende ingresar es menor o igual que cero, el método no modificará el valor de la variable saldo y devolverá false.

Sobrecarga de métodos


La sobrecarga de métodos consiste en poner varios métodos con el mismo nombre en la misma clase, pero siempre con una lista de argumentos distinta. No puede haber dos métodos que se llamen igual con la misma lista de argumentos.

Ejemplo: 

public bool NuevoIngreso(single cantidad)
{...}

public int NuevoIngreso(double cantidad, double argumento2)
{...}

public int NuevoIngreso(single cantidad, double argumento2)
{...}

Lo que diferencia las listas de argumentos de las diferentes sobrecargas no es el nombre de las variables, sino el tipo de cada una de ellas. Por ejemplo, la siguiente sobrecarga tampoco sería válida:

public bool NuevoIngreso(single num)
{...}

A pesar de que el argumento tiene un nombre distinto (num en lugar de cantidad), es del mismo tipo que el del método del ejemplo, por lo que el compilador tampoco sabría cuál de las dos sobrecargas ejecutar.

¿Qué sobrecarga ejecutará si se efectúa la siguiente llamada?

MisCuentas.NuevoIngreso(200.53);

El número 200.53 puede ser double, o single. Para números decimales, el compilador ejecutará la sobrecarga con el argumento de tipo double. En el caso de números enteros, el compilador ejecutará la sobrecarga cuyo argumento mejor se adapte con el menor consumo de recursos (int, uint, long y unlong, por este orden). Si deseamos que, se ejecute la sobrecarga con el argumento de tipo single, tendríamos que añadir un sufijo al número para indicarle al compilador cuál es el tipo de dato que debe aplicar para el argumento:

MisCuentas.NuevoIngreso(200.53F);

Los sufijos para literales de los distintos tipos de datos numéricos son los siguientes:

L (mayúscula o minúscula): long ó ulong, por este orden;
U (mayúscula o minúscula): int ó uint, por este orden;
UL ó LU (independientemente de que esté en mayúsuculas o minúsculas): ulong;
F (mayúscula o minúscula): single;
D (mayúscula o minúscula): double;
M (mayúscula o minúscula): decimal;

Argumentos pasados por valor y por referencia


Puede que necesitemos que los métodos NuevoIngreso y NuevoGasto devuelvan el saldo nuevo, además de true o false. ¿Es posible hacerlo?: no se puede, ya que un método no puede retornar más de un valor. Sin embargo, sí es posible hacer que un método devuelva datos en uno o varios de sus argumentos. Pasando esos argumentos por referencia. Me explicaré mejor: un método puede aceptar argumentos de dos formas distintas (en C# son tres, aunque dos de ellas tienen mucho que ver): argumentos pasados por valor y argumentos pasados por referencia.

Cuando un método recibe un argumento por valor, se crea una copia local de la variable que se ha pasado en una nueva dirección de memoria. Así, si el método modifica ese valor, la modificación se hace en la nueva dirección de memoria, quedando la variable original sin cambio alguno. Por ejemplo, si escribimos el método NuevoIngreso de este modo:

public bool NuevoIngreso(double cantidad)
{
    if (cantidad <=0)
        return false;

    this.saldo += cantidad;
    cantidad=this.saldo;
    return true;
}

Si el saldo era 100, y se efectúa la siguiente llamada.

double dinero=365.88;
MisCuentas.NuevoIngreso(dinero);
Console.Write(dinero);

La salida sería 365.88, es decir, la variable dinero no ha sido modificada, ya que se ha pasado al método por valor (en C#, si no se indica otra cosa, los argumentos de los métodos se pasan por valor).

Sin embargo, si escribimos el método del siguiente modo para que reciba los valores por referencia:

public bool NuevoIngreso(ref double cantidad)
{
    if (cantidad <=0)
        return false;

    this.saldo += cantidad;
    cantidad=this.saldo;
    return true;
}

Y se modifica también el código:

double dinero=365.88;
MisCuentas.NuevoIngreso(ref dinero);
Console.Write(dinero);

La salida en la consola sería 465.88 pues ahora, la variable cantidad apunta a la misma zona de memoria a la que apunta la variable dinero. Por este motivo, cualquier modificación que se haga sobre la variable cantidad afectará también a la variable dinero, ya que dichas modificaciones se harán en la zona de memoria reservada para ambas.

Las variables que se pasen a un método por referencia deben de inicializarse  previamente, pues el programa no se habría compilado, si no se hubiera inicializado antes la variable dinero. Para pasar por referencia argumentos con un  valor inicial que no nos interesa, es posible utilizar out en lugar de ref. Por ejemplo, imagina que queremos devolver en otro argumento el valor del saldo redondeado. Habría que hacerlo así:

public bool NuevoIngreso(ref double cantidad, out int redondeado)
{
       redondeado=(intMath.Round(this.saldo);
       if (cantidad <=0)
             return false;

       this.saldo += cantidad;
       cantidad=this.saldo;
       redondeado=(intMath.Round(this.saldo);
       return true;
}

Y modificar el código que hacía la llamada:

double dinero=365.88;
int redoneo;
MisCuentas.NuevoIngreso(ref dinero, out redondeo);
Console.Write(redondeo);

Ahora la salida en la consola sería 367. Es necesario fíjarse que la variable redondeo no ha sido inicializada antes de efectuar la llamada al método (no ha recibido ningún valor). Por otra parte, este argumento debe recibir algún valor antes de salir del método, por lo que se asigna antes del if y luego se asigna otra vez después de hacer el ingreso. Sin embargo, la variable dinero sí ha sido inicializada antes de invocar el método, puesto que el método necesitaba saber cuánto había que ingresar, pero no necesita saber nada del valor redondeado, pues este se calculará a partir del saldo.

Métodos static


Los métodos static, son aquellos que se pueden ejecutar sin necesidad de instanciar la clase donde está escrito. Pues un  método estático existe en una clase como un todo, más que en una instancia específica de la clase. El hecho de que el método Main tenga que ser static no es un capricho, ya que, de lo contrario, el CLR no sería capaz de encontrarlo pues antes de que se ejecute la aplicación, lógicamente, no puede haber instancias de ninguna de las clases que la componen.

Estos métodos suelen usarse para hacer una serie de operaciones globales que tienen más que ver con la clase como tal, que con una instancia específica de la misma: por ejemplo, si tenemos una clase Moto y queremos listar todas las marcas de motos que hay en el mercado, lo más propio es un método static. Pues no es necesario instanciar un objeto de esa clase, si solamente queremos ver las marcas disponibles.  

Otro ejemplo:


    class LimiteTarjeta
    {
        public static ushort Limite()
        {
            return 300;
        }

        // Aquí irían más miembros de la clase
    }

    class LimiteTarjetaApp
    {
        static void Main()
        {
            Console.WriteLine("El límite de la tarjeta es: {0}",
                LimiteTarjeta.Limite());

            string a=Console.ReadLine();
        }
    }

Para hacer que un método sea static hay que poner esta palabra después del modificador de acceso (si lo hay) y antes del tipo de retorno del método. Este método devolvería el límite que tienen todas las tarjetas para extraer dinero en un sólo día. No se ha instanciado ningún objeto de la clase LimiteTarjeta, sino que se ha puesto directamente el nombre de la clase.

No hay comentarios:

Publicar un comentario