# Introducción a las clases y objetos
## Introducción a las clases en C#

Como hemos dicho, C# es un lenguaje orientado a objetos. A diferencia de lenguajes como C++ o Python en los que la orientación a objetos es opcional, en C# y al igual que en Java, la orientación a objetos es ineludible, de hecho cualquier método o variable está contenida dentro de un objeto. Y el concepto fundamental en torno a la orientación a objetos es la clase.
Una clase es como una plantilla que describe cómo deben ser las instancias de dicha clase, de forma que cuando creamos una instancia, ésta tendrá exactamente los mismos métodos y variables que los que tiene la clase. Los datos y métodos contenidos en una clase se llaman miembros de la clase y se accede a ellos siempre mediante el operador "." . En el siguiente ejemplo, se definirá una clase, Clase1 y en el método Main se creará una instancia de Clase1 llamada MiClase. Una buena idea es jugar un poco con el código para ver que la instancia de la clase efectivamente tiene los mismos miembros que la clase Clase1 (que sería la plantilla de la que hablábamos antes)
los identificadores public delante de los tipos que hay dentro de Clase1 son necesarios para luego poder ser llamados desde otra clase, como en este caso, que estamos llamando a los miembros de una instancia de Clase1 desde UsoClase. Pero en las clases no solo hay variables, también podemos incluir métodos.
Podemos hacer más cosas con las clases, como heredar otras clases o implementar interfaces, pero en este capítulo nos centraremos en el uso de métodos y variables.

### Métodos

Los métodos, también llamados funciones, son trozos de código que reciben unos datos, hacen algo con esos datos, y a veces devuelven algún valor. En C#, todos los métodos se encuentran contenidos dentro de un objeto.
La estructura mínima de un método tiene las siguientes partes:
de forma que el siguiente método:
devuelve un tipo double, tiene por nombre Divide, los parámetos son a y b, ambos del tipo double, y el cuerpo del método es simplemente "return a/b;".
Cuando queramos llamar a un método, debemos simplemente poner el nombre del método y sus argumentos dentro de un paréntesis separados por comas. Para llamar al método Divide declarado antes, simplemente debemos escribir Divide(8, 2);
Según lo que hemos visto, el ejemplo del método Divide completo necesita tener una clase donde definirse y un método Main donde ejecutarse.

### Pasando valores a los métodos
#### Parámetros

La declaración formal de parámetros también define variables. Hay cuatro tipos de parámetros: parámetros por valor, por referencia, parámetros de salida, y arreglos de parámetros.

#### Paso por valor

El paso de parámetros por valor es usado por defecto para pasar parámetros a métodos. Cuando se pasa un parámetro por valor a una función realmente se está pasando una copia de dicho parámetro, por lo que las modificaciones que le hagamos al parámetro dentro del método no afectarán al parámetro original. El ejemplo
muestra un método F que tiene un parámetro por valor llamado p. El ejemplo produce la salida:
aunque el valor del parámetro p haya sido modificado dentro del método, éste parámetro solamente tenía una copia del valor del parámetro a que pasamos al método; por lo que cuando imprimimos el parámetro a vemos que éste parámetro ha mantenido su valor original.

#### Paso por referencia

El paso de parámetros por referencia es la contraposición lógica al paso por valor. En el paso por referencia no se realiza ninguna copia del objeto, sino que lo que se le pasa a la función es una referencia del objeto, de forma que el parámetro pasa directamente a la función y cualquier modificación sobre el parámetro dentro de la función afectará al parámetro original
muestra un método swap que tiene dos parámetros por referencia. La salida producida es:
La palabra clave ref debe de ser usada tanto en la declaración formal de la función como en los usos que se hace de ésta.

#### Parámetro de salida

El parámetro de salida es similar al parámetro por referencia, salvo que el valor inicial de dicho argumento carece de importancia. Un argumento de salida se declara con el modificador out. El ejemplo
muestra un método Divide que incluye dos parámetros de salida. Uno para el resultado (variable result) de la división y otro para el resto (variable resid). Vemos que estos resultados son asignados a las variables respuesta y residuo respectivamente.

#### Arreglo de parámetros

Habrá ocasiones que necesitemos pasar varios parámetros a un método (o función) pero no sabremos con anticipación cuantos parámetros tendremos que pasar; para esto podremos usar un arreglo de parámetros. Un arreglo de parámetros permite guardar una relación de varios a uno: varios argumentos pueden ser representados por un único arreglo de parámetros. En otras palabras, los arreglos de parámetros permiten listas de argumentos de tamaño variable.
Un arreglo de parámetros se declara con el modificador params. Sólo puede haber un arreglo de parámetros en cada método, y siempre debe ser el último parámetro especificado. El tipo del arreglo de parámetros debe ser siempre un tipo arreglo unidimensional. Al llamar a la función se puede pasar uno o varios argumentos del tipo del arreglo. El ejemplo
muestra un método F que toma un número variable de argumentos int, y varias llamadas a este método. La salida es:
La mayoría de los ejemplos presentes en este capítulo utilizan el método WriteLine de la clase Console. El comportamiento para las sustituciones, como muestra el ejemplo
se consigue usando un arreglo de parámetros. El método WriteLine proporciona varios métodos sobrecargados para el caso común en el que se pasa un pequeño número de argumentos, y un método que usa un arreglo de parámetros.

### Modificadores public y static

El modificador public lo hemos utilizado anteriormente. Se puede utilizar en la declaración de cualquier método o variable, y como es de esperar, produce el efecto de que el campo afectado se vuelve público, esto es, se puede utilizar desde otras clases
Si por ejemplo intentamos declarar el método Divide sin el modificador public, obtendremos un error en tiempo de compilación. El modificador complementario de public es private, que provoca que el método o dato solo sea accesible desde la clase en la que está declarado. Si no se especifica nada, se toma por defecto el modificador private
De esta forma podríamos separar las clases Metodo y Principal en dos archivos separados, llamados por ejemplo metodo.cs y principal.cs . Para compilar esto, bastará compilar ambos archivos al mismo tiempo, de forma similar a esto: mcs principal.cs metodo.cs
Además, tampoco es necesario crear una instancia de la clase sólo para acceder a un método declarado en ella. Para eso debemos anteponer a la declaración del método el modificador static. Los métodos estáticos se caracterizan por no necesitar una instancia de la clase para cumplir su función, pero como contrapartida, no pueden acceder a datos propios de la clase.
Los métodos estáticos se utilizan en multitud de situaciones. Por ejemplo, el método Console.WriteLine o las funciones de la librería matemática estándar no son más que métodos estáticos de sus respectivas clases.

### Constructores e instancias de una clase

Como hemos visto, las instancias de una clase se crean con la sintaxis
donde nombreclase es el nombre que le hemos dado a la definición de la clase, argumentos es una lista de argumentos posiblemente vacía y objeto es el nombre que queremos darle a la instancia de la clase.
Una vez creada una clase, sus miembros se inicializan a sus valores predeterminados ( cero para valores numéricos, cadena vacía para el tipo string, etc. ). La siguiente clase representa un punto sobre el plano, de forma que tiene dos valores públicos X e Y, y un método que calcula la distancia al origen del punto (módulo)
Ahora bien, la forma en la que se crea la instancia, es decir, inicializando los datos a cero (ejercicio: comprobar esto), se puede personalizar, de forma que podemos construir nuestro propio constructor que le diga a la clase los valores por defecto que debe tomar. Esto se realiza simplemente escribiendo dentro de la clase un método que tenga el mismo nombre que la clase y en el que no se especifica el valor devuelto. La clase Punto con un constructor sería así:
de forma que ahora al crear una instancia de la clase se crea el punto (1,1) en lugar del (0,0), que era el que se creaba por defecto. De esta forma, al crear la instancia, par ya contendrá los valores (1,1) .
En la práctica se utilizan mucho constructores con parámetos, de forma que al crear la instancia se le asignan valores según los parámetros. La siguiente implementación de Par contiene un constructor que acepta un par de valores, que servirán para inicializar los valores A y B
También tenemos la posibilidad de declarar una clase con varios constructores (cada uno con diferentes parámetros) Lo que hará el compilador de C# es buscar el constructor que se adecúe a los parámetros que le llegan, y ejecutarlo como si fuera un método más. Dependiendo de la llamada que se haga en el "new", usaremos un constructor u otro.

### Sobrecarga de métodos

En C#, al igual que en C++ y en Java es posible definir varios métodos con el mismo nombre pero con distintos parámetros, de forma que el compilador decide a cuál se llama dependiendo de los parámetros que le lleguen.
Esto es muy práctico, pues no tienes que renombrar cada función según el tipo de valor que acepta. El siguiente ejemplo implementa un par de métodos que elevan al cuadrado el valor que reciben, y se implementan para tipos double y para int. En C, que es un lenguaje que no soporta sobrecarga de métodos, se tendría que haber llamado distinto a ambos métodos, por ejemplo alcuadrado_double y alcuadrado_int

### La palabra reservada this

La palabra reservada this sirve para hacer referencia a miembros de la clase en caso de que se quiera especificar, ya sea por motivos de colisión de nombres o por la claridad del código. Su sintaxis es
donde campo es la variable de la clase a la que queremos hacer referencia.
En el siguiente ejemplo, declaramos un constructor para la clase Punto, que toma dos argumentos X e Y. Entonces es obligado el uso de this para distinguir entre el X de la clase y el X tomado como parámetro

## Propiedades e indizadores
### Propiedades

Las propiedades son una característica de C# que permiten aparentemente el acceso a un miembro de la clase mientras mantiene el control asociado al acceso mediante métodos.
Para los programadores de Java hay que decir que esto no es más que la formalización del patrón de asignación (setter) y método de lectura (getter)
Las propiedades son como métodos que se declaran dentro de un bloque asociado a una variable mediante las palabras reservadas get (se encarga de devolver algo cuando se llama al tipo que lo contiene ) y set (que hace algo cuando se le asigna un valor a la variable que lo contiene. Este valor viene especificado en la variable value )
En realidad, lo que se hace es declarar una variable privada de forma que no se puede acceder de forma directa, y se crean dos métodos ( o uno si solo se requiere acceso de lectura) que permiten acceder al contenido de la variable y tal vez modificarla. Si no queremos que se pueda modificar la variable, no incluímos el método "set" y ya tendríamos propiedades de sólo lectura.

### Indexadores

Hemos visto, en el apartado en el que tratamos las propiedades, que podemos acceder a una variable privada de una clase a través de eventos que nos permiten controlar la forma en la que accedemos a dicha variable.
Los indexadores nos van a permitir hacer algo parecido. Nos van a permitir acceder a una clase como si se tratara de un arreglo. Lo vemos de forma más sencilla con un ejemplo:
Tenemos una clase PruebaIndexadores en la que hay un array llamado "tabla", declarado como privado, por lo que no podremos acceder a él desde fuera de nuestra clase. Pero hemos declarado también un indexador (public int this [int indice]), que nos permitirá acceder a él de forma más controlada.
Para probar esta clase, creamos otra clase con un punto de entrada (public static void Main), que será donde hagamos las pruebas.
Primero creamos un objeto de la clase PruebaIndexadores:
Luego accedemos a una posición del indexador:
Esta línea lo que hace es llamar al indexador, pasándole como parámetro el índice, en este caso 3. Al ser una consulta de lectura, se ejecuta el código que haya en la parte "get" del indexador. Una vez ejecutado, lo que nos aparece por pantalla es esto:
Vamos ahora a hacer un cambio en la tabla:
Lo que se ejecuta ahora es la parte "set" del indexador. Lo que aparecerá en pantalla una vez ejecutado esto será:
Nótese que tenemos que hacer explícitamente el acceso al array (tabla[indice]=value) en el set, ya que el indexador no tiene forma de saber qué variable se supone que tiene que manejar. Si no pusiéramos esa línea, en realidad el indexador no cambiaría el valor del array.
Para comprobar que realmente se ha hecho el cambio, volvemos a acceder al indexador:
Y esta vez nos aparecerá esto: