sábado, 26 de febrero de 2022

Curso avanzado de C#.Constructores y métodos

A parte de la asignación de valores después de instanciar una clase, hay otra forma, de  asignar dichos valores a los miembros de un objeto. Esto se hace a través de un constructor.  Un constructor es un método que se llama siempre que se crea una instancia de un objeto. Podemos utilizar constructores en nuestros archivos de clase para establecer valores iniciales para algunos o todos los datos miembros en los objetos que creamos. Si no definimos un constructor C# crea su propio constructor. El constructor por defecto establece los valores de Cada variable miembro a su valor por defecto. 

Los constructores tienen una sintaxis específica, como se muestra aquí: 

  // sintaxis para un constructor
 public NombreClase()
 {
       //Instrucciones de inicialización opcionales;
 }
 // Definición de la clase estudiante
 class Estudiante
 {
   public static int CuentaEstudiante;
    public string Nombre;
    public string Apellido;
    public string Grado;
        // Constructor 1 de la clase Estudiante
        public Estudiante(string nombre, string apellido, string grado)
        {
            this.Nombre = nombre; this.Apellido = apellido; this.Grado = grado;
        }
        // Constructor n de la clase Estudiante
        public Estudiante()
        {
        }
}

En el ejemplo anterior hay dos constructores. Los constructores son públicos porque deben ser accesibles fuera de la clase.  Esto es necesario para permitir que el objeto se inicialice cuando se crea. El constructor toma el mismo nombre que la clase. Dentro de las llaves adjuntas, las declaraciones de inicialización son opcionales. Un constructor es un método pero no incluye ningún tipo de retorno, ni siquiera nulo. Incluir un tipo de retorno en un constructor es una sintaxis incorrecta y generará una advertencia del compilador.

El primer constructor es el no predeterminado y acepta tres valores de cadena y los utiliza para inicializar las variables miembro. El segundo constructor es predeterminado y no incluye declaraciones ni toma argumentos.

Este es el tipo de constructor que el compilador se genera si el desarrollador no crea otros constructores. Este constructor inicializa las variables miembro con sus valores por defecto. Cuando creamos un nuevo objeto, el compilador tiene la opción de usar cualquiera de los constructores disponibles declarados en la clase, o ninguno. En el ejemplo anterior podemos llamar al constructor no predeterminado, pasando los valores del nombre, apellido y grado. Si no proporcionamos ningún valor, se llamará al constructor por defecto. Además, no podemos llamar al  constructor no predeterminado anterior
si sólo rellenamos algunos valores. Es todo o nada. Los constructores predeterminados se utilizan solo cuando no se llama a ningún otro constructor.  

Definiendo métodos

Los métodos son los componentes de una aplicación que desglosar los requisitos informáticos de nuestra aplicación en piezas más pequeñas de funcionalidad.  Una buena práctica de programación dicta que los métodos deben realizar funciones discretas en nuestro código y que el método realiza solo lo que es  necesario para lograr el resultado deseado. Algunos argumentan que codificar de esta manera genera un código que ocupa más recursos  debido a que el sistema operativo debe mantener los indicadores de instrucciones y las referencias para todas las llamadas al método función,  pero hace que nuestro código sea más fácil de leer y mantener. Si nuestro programa está generando errores, es mucho más fácil localizarlos. 


Un método es un trozo de código definido por un nombre, una firma, un bloque de declaración  y una variable de retorno opcional. La sintaxis de un método siguiente: 

// sintaxis de un método

modificador return type nombre_metodo(optional argumentos)
{
   intrucciones;
}

En el ejemplo anterior, el modificador puede ser público, privado, etc. El tipo de retorno puede ser cualquier tipo de C# válido (por valor o referencia) pero también puede ser la palabra clave void, que indica que el método no devuelve ningún valor. El nombre se usa para identificar el método en el código y se utiliza para llamar al método. Los los paréntesis incluyen argumentos opcionales para el método. Un método puede tener ninguno o varios argumentos.

La llaves encierran la funcionalidad del método en forma de instrucciones. Estas instrucciones pueden ser cualquiera de C# y también puede incluir una declaración de devolución opcional return sólo si el método tiene declarado un tipo de retorno. 

Es ilegal incluir una declaración de devolución en un método declarado como void. A continuación crearemos dos métodos para la clase de Estudiante. Un método recuperará el nombre y apellido del estudiante, los concatena y devuelve el nombre. El método de llamada no devuelve valor, pero imprimirá el nombre en la ventana de la consola. 

class Estudiante
 {
   public static int CuentaEstudiante;
    public string Nombre;
    public string Apellido;
    public string grado;
   // sintaxis de un método
    public string concatenaNombre()
    {
      string NombreCompleto = this.Nombre + " " + this.Apellido;
        return NombreCompleto;
    }
    // sintaxis de un método
    public void MuestraNombre()
    {
      string nombre = concatenaNombre();
        Console.WriteLine(nombre);
        Console.ReadLine();
    }
}
class Programa
{
   static void Main(string[] args)
    {
      Estudiante primerEstudiante = new Estudiante();
        Estudiante.CuentaEstudiante++; Estudiante segundoEstudiante = new Estudiante();
        Estudiante.CuentaEstudiante++; primerEstudiante.Nombre = "Juan";
        primerEstudiante.Apellido = "González"; primerEstudiante.grado = "sexto";
        segundoEstudiante.Nombre = "Antonio"; segundoEstudiante.Apellido = "Fernández";
        segundoEstudiante.grado = "dos"; primerEstudiante.MuestraNombre();
    }
}

Análisis

Este ejemplo muestra el uso de métodos tanto dentro de la clase como en el método principal de la aplicación. Hemos añadido dos métodos. El primer método se llama concatenaNombre() y devuelve un valor de cadena. Lo hemos declarado público, y con un valor de retorno de cadena. El método no tiene parámetros simplemente declara una variable llamada NombreCompleto de tipo cadena. Luego usa la funcionalidad de concatenación de cadenas de C# y combina la variable Nombre con un espacio y la variable Apellido para crear el nombre completo para el alumno.

Asigna esto a la variable NombreCompleto y luego la envía a la función de llamada con la declaración de retorno Return. La función que llama a concatenaNombre()  es otro método simple que hemos creado, llamado MuestraNombre() utiliza el tipo de retorno void, lo que significa que no devuelve un valor y no tiene una declaración de retorno en el bloque de instrucción. Declara una variable de tipo cadena llamada nombre y utiliza el valor de retorno del método concatenaNombre() para Asignar a la variable nombre. Luego escribe el valor en la ventana de la consola.

En el método principal de la aplicación, agregamos una nueva declaración al final del método, primerEstudiante.MuestraNombre(); Esta declaración utiliza el objeto primer estudiante Objeto creado en el código y llama a su método público MuestraNombre(). La ejecución cambia a este método en el código del objeto. El método crea una variable, y luego en la instrucción de asignación, llama al método concatenaNombre() del mismo objeto. 

La ejecución ahora pasa a este método donde La variable NombreCompleto se crea y se utiliza en una instrucción que concatena el nombre y el apellido.
Debido a que el nombre de cadena de declaración concatenaNombre(); ha sido el responsable de llamar a este método, el compilador ha mantenido un seguimiento en la pila de memoria y sabe dónde está el valor de retorno que necesita la declaración de retorno de concatenaNombre(), cuando finaliza ese método, devuelve el valor al método que le llamó y asigna a la variable la concatenación generada. Ahora el método MuestraNombre () ya puede mostrar el nombre completo en la ventana de la consola. 


Los métodos  pueden aceptar varios valores entrantes. Esto es posible mediante el uso de parámetros y argumentos. La firma del método que acepta valores es de este tipo: 

// sintaxis de un método que toma valores

 modificador return tipo nombre(parametros)
 {
   instrucciones;
}

Desafortunadamente, el uso de los términos parámetros y argumentos suele ser mal utilizado. Cuando se trata de métodos, se utiliza el término parámetro para identificar los marcadores de posición en la firma del método, mientras que los argumentos son los valores reales que se pasan al método. 

// ejemplo de firma de métod que acepta valores
 public int suma(int num1, int num2)
 {
   return num1 + num2;
 }
 int ValorSuma = suma(2, 3);


En el ejemplo anterior, el método suma es público y devuelve un valor entero. Dentro de los paréntesis vemos int num1, int num2. Estos son los parámetros del método. Debemos indicar el tipo de datos que se espera de estos parámetros. Esto ayuda al compilador a capturar asignaciones inválidas cuando se llama al método es  llamado; num1 y num2 son los nombres de los parámetros. La última línea en el código de ejemplo llama al método de suma y pasa dos valores. Estos dos valores son los argumentos de la llamada al método. Podemos ver ahora de dónde viene la confusión  y por qué estos dos términos se usan indistintamente a veces.

Hay que pensar en los parámetros como en marcadores de posición en la firma del método, y los argumentos son los valores que se pasan en a estos marcadores de posición. Los métodos pueden recibir objetos como argumento. Otra distinción importante, es cuando se pasan argumentos por valor, se pasa una copia del valor al método, mientras que al pasar argumentos por referencia, se pasa una referencia (una dirección de memoria) y no se pasa todo el objeto.

Podríamos ocupar bastante memoria si pasamos un objeto entero a un método. Cuando pasamos argumentos por valor, el método actúa sobre una copia local de la variable y no cambia el valor original. Al pasar un argumento por referencia si actuamos sobre el argumento, modificamos su valor. Esto se ve en el siguiente ejemplo. 

Pasando valores a métodos [value_type_passing] 

class Estudiante
 {
        public string Nombre;
        public string Apellido;
        public string grado;
 }
    class Programa
    {
        static void Main(string[] args)
        {
            int num1 = 2; int num2 = 3;
            int resultado;
            Estudiante primerEstudiante = new Estudiante();
            primerEstudiante.Nombre = "Juan";
            primerEstudiante.Apellido = "González";
            primerEstudiante.grado = "seis";
            resultado = suma(num1, num2);
            Console.Write("La suma es: ");
            Console.WriteLine(resultado);
            // devuelve 5
            Console.WriteLine();
            cambiaValores(num1, num2);
            Console.WriteLine();
            Console.WriteLine("Regreso a cambiaValores()");
            Console.WriteLine(num1);
            // devuelve 2
            Console.WriteLine(num2);
            // devuelve 3
            Console.WriteLine();
            Console.WriteLine("El nombre de primerEstudiante es " + primerEstudiante.Nombre);
            cambiaNombre(primerEstudiante);
            Console.WriteLine();
            Console.WriteLine(" El nombre de primerEstudiante es " + primerEstudiante.Nombre);
            Console.ReadLine();
        }

        static int suma(int valor1, int valor2)
        {
            Console.WriteLine("En el método suma()");
            return valor1 + valor2;
        }

        static void cambiaValores(int valor1, int valor2)
        {
            Console.WriteLine("En el método cambiaValores()");
            Console.WriteLine("valor1 es " + valor1);
            // devuelve 2 Console.WriteLine("valor2 is " + valor2);
            // devuelve 3 Console.WriteLine();
            Console.WriteLine("Cambiando valores");
            valor1--; valor2 += 5;
            Console.WriteLine();
            Console.WriteLine("valor1 es ahora" + valor1);
            // devuelve 1 Console.WriteLine("valor2 is now " + valor2);
            // devuelve 8
        }
        static void cambiaNombre(Estudiante refValue)
        {
            Console.WriteLine();
            Console.WriteLine("En cambiaNombre()");
            refValue.Nombre = "Jorge";
        }
}

Análisis

La clase Estudiante está simplificada para este ejemplo, solo tenemos tres campos miembro en el método principal del programa, declaramos cuatro variables, tres de tipo int y una de tipo estudiante. Asignamos valores a num1, num2 y a los miembros del objeto Estudiante llamado primerEstudiante. La variable de resultado se asignará más adelante. El primer método al que llamamos es el método que suma, pasamos a num1 y num2 como argumentos al método.

Dentro de suma(), escribimos un mensaje para indicar que estamos dentro de este método. A continuación, agregamos los dos valores y devolvemos el resultado al método que lo ha llamado. Después mostramos ese resultado en la ventana para ver como el método suma() ha sumado ambos valores, luego mostramos un ejemplo de cómo el método utiliza copias de los valores si estos son suministrados por valor. Llamamos al método cambiaValores() donde le pasamos de nuevo num1 y num2. En cuya salida mostramos los valores numéricos de los dos parámetros valor1 y valor2.

Con esto demostramos que pasamos los mismos valores para num1 y num2. Luego  indicamos que cambiaremos estos valores y decrementamos en 1 el valor1 e incrementaremos en 5 el valor2. Finalmente el método cambiaValores(), genera los nuevos valores para valor1 y valor2. 

De vuelta a la función main, mostramos los valores de num1 y num2 de nuevo para mostrar que estas variables no han sido cambiadas por el método cambiaValores() solo se han cambiado las copias locales, no los valores originales. 

Para ver cómo se ven afectados los tipos por referencia en las llamadas a métodos, ahora mostramos el primer nombre del El objeto primerEstudiante que creamos para mostrar que su valor es Juan, el valor que se le asignó al principio el código. Luego llamamos a otro método llamado cambiaNombre(), que toma una variable por referencia de tipo Estudiante, y pasa el primer estudiante como tipo por referencia al método. Dentro de este método, cambiamos el nombre del primer estudiante a Jorge. Después de volver del método, escribimos el primer nombre del primer estudiante y vemos que de hecho lo hemos cambiado. Esto muestra claramente que al pasar una variable como referencia a un método, obtenemos como resultado el cambio del valor original, muy diferente del tipo pasado por valor.  La Figura muestra la salida del código anterior. 



No hay comentarios:

Publicar un comentario