capitulo 03 - diseñoaplicacionesoop

Upload: necrotear

Post on 07-Jul-2015

286 views

Category:

Documents


1 download

DESCRIPTION

ASP.NET Programación con C#

TRANSCRIPT

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos.3.1. Clases y Estructuras.Dentro del Common Type System (CTS) en .Net Framework, tenemos dos construcciones bsicas: las clases y las estructuras. En esencia, ambas son estructuras de datos que encapsulan un conjunto de datos y comportamientos relacionados como una unidad lgica. Se llaman miembros de la clase o estructura, a los datos y comportamientos que incluyen: mtodos, propiedades, eventos, etc. Las clases y estructuras se utilizan para crear instancias u objetos en tiempo de ejecucin. Se puede crear tantas instancias como se desee de un tipo de clase y, cada una de estas instancias, contener datos distintos. Una clase es un objeto que es creado como un tipo por referencia. Cuando creamos un objeto de esa clase (instancia), la variable a la que se asigna slo incluye una referencia al espacio en memoria donde se encuentra la clase. Cuando la referencia se asigna a una nueva variable, esta contiene igualmente la referencia al objeto original. En este caso cuando una de las dos variables cambia el contenido de su valor o valores, automticamente cambia la otra. Ver cdigo y esquema para la Clase Persona.protected void Page_Load(object sender, EventArgs e) { //LLamamos a la clase Persona y realizamos una instancia en la variable DatosPer Persona DatosPer= new Persona("Pedro", "Lpez"); lblVer.Text = "El nombre completo es: " + DatosPer.Nombre + " " + DatosPer.Apellidos; } class Persona { public Persona(string Nomb, string Apell) { Nombre = Nomb; Apellidos = Apell; } public string Nombre { get; set; } public string Apellidos { get; set; } }

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 1

Esquema del resultado en memoria al instanciar una clase:Clase PersonaInstancia de la Clase Persona

Variables de la clase Persona string Nombre string ApellidosValores de las variables

Valores por Referencia

Variable de la Instancia AB13 43CB

Direcciones Hexadecimales

Como se puede ver en el esquema, los datos de la clase estn en un lugar y las referencias a ese lugar en otro. Cuando accedemos a la clase para grabar un dato o ver un valor, el sistema mira la referencia (direcciones hexadecimales) y a continuacin saca o coloca el valor en el sitio que le indica esa referencia. Cuando realizamos una copia de la instancia, slo se copian las referencias y no los datos. Ambas, copia y original, apuntan a los mismos datos. Por eso, un dato cambiado en cualquiera de las dos afecta a la otra. Una estructura es un objeto que es creado como un tipo por valor. Cuando se crea la estructura, la variable que se asigna incluye los datos y la propia estructura. Si asignamos esta variable a otra variable, a diferencia de las clase, hace una copia ntegra del objeto (en las clases slo copia las referencias). En este caso e igualmente a diferencia de las clases, los cambios en una de las variables no afecta a la otra. Ver cdigo y esquema.protected void Page_Load(object sender, EventArgs e) { //LLamamos a la clase Persona y realizamos una instancia en la variable DatosPer Persona DatosPer= new Persona("Pedro", "Lpez"); lblVer.Text = "El nombre completo es: " + DatosPer.Nombre + " " + DatosPer.Apellidos; } struct Persona { public string Nombre, Apellidos; public Persona(string Nomb, string Apell) { Nombre = Nomb; Apellidos = Apell; } }

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 2

Esquema de instanciar una estructura

En las estructuras, podemos ver, que a pesar de ser instanciadas de la misma forma, su comportamiento es diferente. En las estructuras, la variable de la instancia, en el ejemplo DatosPer, contiene los datos y las variables de la estructura, a diferencia de la clase que slo contena las referencias a los datos. Bsicamente las clases se utilizan cuando necesitamos un comportamiento ms complejo o datos que se piensan modificar una vez creado el objeto.

Estructura PersonaInstancia de la Estructura Persona

Variables de la clase Persona string Nombre string ApellidosValores de las variables

Las estructuras son ms indicadas cuando manejamos pequeas estructuras de datos y no se piensan modificar una vez creados. Ms adelante se ver un resumen de cuando es mejor una eleccin u otra. Para poder trabajar en programacin orientada a objetos (POO) dentro de .NET usaremos las clases. La POO tiene en la clase un mecanismo potente para realizar sus funciones e incluye dos caractersticas igualmente importantes: encapsulamiento y herencia. Cuando trabajamos en un programa orientado a objetos, lo que realmente estamos creando es un conjunto de clases, desde las cuales se crean los objetos necesarios para nuestro programa.

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 3

3.2. Las Clases.Qu es un objeto? Por ejemplo, si quisiramos hacer un flan, tendramos que el molde es la clase y los flanes son los objetos. Si queremos hacer un flan de vainilla tenemos unos ingredientes: leche, azcar, vainilla, etc, pero no todos los flanes tendrn la misma proporcin de ingredientes. Adems, no tienen porque todos los flanes ser de vainilla, tambin pueden ser de huevo. Una clase equivale a generalizar un tipo especfico de objetos, pero cada objeto que construyamos de esa clase contendr sus propios datos. El objeto en la clase es creado en el momento en que se invoca mediante el operador new: Flan vainilla = new Flan(); Una aplicacin de C# tpica se compone de clases definidas por el programador, junto con clases de .NET Framework. Una clase es en s misma un tipo personalizado por el programador mediante la agrupacin de variables de otros tipos, tanto de tipos bsicos como de tipos desarrollados por otros programadores. En la clase se define el tipo y el comportamiento del tipo. Si la clase no se declara como esttica se instancia con una variable, usando la palabra clave new, tal y como hemos visto antes. Esa variable declarada para ese tipo es administrada por el CLR hasta que termina su mbito de ejecucin, en cuyo caso, el CLR la marca para recoleccin y el Garbage Collector la limpiara de la memoria. Por el contrario, si es esttica, slo existe una copia de la clase en memoria y no permite instanciarla sobre una variable. Si queremos acceder a ella es necesario hacerlo a travs de la propia clase y no por una copia de una variable instanciada. A diferencia de las estructuras, las clases permiten herencia, que es un pilar bsico en la programacin orientada a objetos. 3.2.1. Cmo se define una clase en C#? Para la definicin de una clase en C# se utiliza la palabra class seguido del nombre de la clase y dentro de las llaves el cdigo. Ejemplo: class Flan { Implementacin de los mtodos, propiedades y atributos de la clase. }

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 4

Cuando se define una clase en C# existe un concepto denominado nivel de acceso que indica desde donde se puede acceder o utilizar la clase. Por ejemplo, una clase declarada como Public, puede ser accedida desde cualquier proyecto, por el contrario, si se declara Private, slo es accesible por el propio contenedor de la clase. El nivel de accesibilidad predeterminada para una clase es Private. Los niveles de acceso van delante de la palabra class. Ejemplo: public class Flan Tabla de Niveles de acceso para la clase.public protected Acceso no restringido. Acceso limitado a la clase contenedora o a los tipos derivados de esta clase. Acceso limitado al proyecto actual. Acceso limitado al proyecto actual o a los tipos derivados de la clase contenedora. Acceso limitado al tipo contenedor.

internal protected internal private

Cualquier mtodo, propiedad o atributos deben de estar siempre contenidos dentro de las llaves de una clase. Aunque muchas veces se habla de que un objeto es una class, en realidad, una clase define un tipo de objeto, pero no es propiamente un objeto. Cuando creamos una estancia de la clase con la palabra reserva new, se crea una referencia al objeto, por ejemplo: Empleado objEm = new Empleado(); En este ejemplo, objEm es una referencia a un objeto basado en Empleado. Esta referencia apunta al nuevo objeto, pero no contiene los datos del objeto, tal y como pudimos ver en el esquema de instancia de una clase al principio del captulo. Podemos crear slo la referencia, sin apuntar a datos, por ejemplo: Empleado objEm; En este caso, el objeto no apunta a ningn dato y si intentamos usar la variable objEm, dara un error de ejecucin. Pero podemos usarlo para el siguiente ejemplo: Empleado objEmBase = new Empleado(); Empleado objEm = objEmBase; En este ejemplo, instanciamos la variable objEmBase y a continuacin le pasamos las referencias de objEmBase a objEm, lo que significa que ambasCaptulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 5

estn apuntando a los mismos datos. Si cambiamos un valor del objeto en una, lo cambiamos automticamente en la otra (valores por referencia). Las clases se agrupan en espacios de nombre (namespace). La palabra clave namespace se utiliza para declarar un mbito. Este mbito permite organizar el cdigo y proporciona una forma de crear tipos globalmente nicos. Un espacio de nombres puede contener varias clases y subclases, as como otros espacios de nombres. Por ejemplo: namespace MisClases { public class ClasePrincipal { // Instrucciones } class ClaseInterna { // Instrucciones } } 3.2.2. Qu son los atributos? Son caractersticas individuales que diferencia un objeto de otro. Es decir, como hemos comentado anteriormente, cada objeto puede tener unos valores diferentes (ingredientes). Se manejan mediante variables que se declaran de un tipo especfico y que deberan ser privadas a la clase. Ejemplo: class Flan { private int Azucar; private int Leche; private string TipoFlan; } En el ejemplo anterior hemos definido tres atributos: dos de tipo int y uno de tipo string. Son privados a la clase y se usarn en los distintos mtodos y propiedades de la clase. Por regla general los atributos de la clase son privados para que los programadores desde fuera no tengan acceso a ellos. Un programador que use nuestra clase Flan no podr acceder directamente a estas variables. Para poder acceder al contenido de un atributo, podemos usar las Propiedades.

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 6

3.2.3. Qu es una Propiedad? Las propiedades tienen un aspecto anlogo a un mtodo. Utilizan descriptores de acceso para controlar cmo se establecen y devuelven valores de los atributos a los que se refieren. Los descriptores son rutinas de cdigo declaradas dentro de la propiedad. El descriptor GET, recupera su valor y el descriptor SET establece su valor. Ejemplo:class Flan { // Definicin de Atributos. private int Azucar; // Definicin de Propiedades. public int CantidadAzucar { get { return Azucar; } set { Azucar = value; } } }

La propiedad tiene que ser public o internal para poder acceder a ellas desde fuera (private suele ser el atributo, pero no es obligatorio). Evidentemente, se aplica la misma norma de modificador de acceso que para el caso de las clases. No tiene porque llevar siempre el get y el set, puede tener slo uno de los dos. Cuando slo tiene el get, se llama propiedad de slo lectura y cuando tiene slo el set, propiedad de slo escritura. En Net Framework 3.5 y superior, las propiedades ya no necesitan tener vinculado obligatoriamente una variable o atributo, aunque se puede usar si se quiere. Hasta la versin 3.5 de Net, cuando definamos una propiedad, estbamos obligados a definir un atributo que era, al fin y al cabo, la variable que contena realmente el valor. Por lo tanto, si slo queremos guardar y leer un valor en una propiedad, podemos realizar el ejemplo anterior de la siguiente forma:class Flan { // Definicin de Propiedades. public int CantidadAzucar { get; set; } }

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 7

3.2.4. Mtodos en C#. Un mtodo es un bloque de instrucciones cuyo objetivo es realizar una tarea concreta. Podemos usar un mtodo para calcular el resultado de una frmula matemtica, para grabar o leer datos en ficheros, para imprimir, etc. Los mtodos tienen que ser definidos dentro de una clase o estructura. En C#, toda instruccin tiene que ser ejecutada dentro de un mtodo. La forma de llamar al mtodo es usando su nombre y el doble parntesis. Por ejemplo: MiMetodo(); Un mtodo es en realidad una parte de cdigo que se decide agrupar para poder ejecutarlo cuando se necesite. Por tanto, el mtodo puede contener cualquier instruccin del lenguaje que se est utilizando, as como variables y dems objetos. Si bien podemos usar variables que nos permiten almacenar datos dentro del mtodo, el mtodo en s no puede guardar valores. Dentro del mtodo, cualquier variable declarada, hace que su uso est restringido al propio mtodo. Estructura de un mtodo:1. Modificador de acceso 2. Tipo de dato devuelto 3. Nombre del mtodo 4. Argumentos de entrada

private void NombreMetodo(argumentos de entrada) { // Instrucciones }

1. Modificador de acceso. El modificador de acceso permite especificar desde donde puede ser accedido el mtodo. Un mtodo slo puede ser llamado desde un objeto que tenga el nivel de acceso adecuado al mtodo. Tipos de acceso: Private. Slo es accesible por el contenedor. Es el nivel de acceso ms restringido. Si no aparece en el mtodo modificador de accedo, el mtodo es por defecto Private. Public. Es accesible para las clases heredadas, para el proyecto en el que se encuentra el mtodo y para cualquier otro proyecto. Es el nivel de acceso ms amplio y se le conoce como acceso no restringido. Protected. Slo es accesible por la clase contenedora y por las clases que heredan de la clase que contiene el mtodo. Internal. Slo es accesible por el ensamblado, es decir por el propio proyecto que contiene el mtodo.Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 8

Protected Internal. Slo es accesible por la clase contenedora del mtodo, as como por las clases que heredan de la clase y por el propio proyecto. 2. Tipo de dato devuelto. Si el mtodo no tiene que devolver ningn valor cuando es invocado, se utiliza la palabra reservada void. Por el contrario, si tiene que devolver un dato, hay que especificar el tipo de dato en lugar de void. Un mtodo acepta cualquier tipo bsico, as como cualquier tipo referenciado. El siguiente ejemplo devolvera un nmero de tipo decimal: private decimal Numero(). Cuando el mtodo no devuelve nada (void), el mtodo ha de ser llamado como vimos al principio, es decir, nombre del mtodo y el doble parntesis. Pero cuando el mtodo devuelve un valor y queremos usar ese valor, debemos de almacenar el valor en una variable del tipo devuelto. Por ejemplo, si el mtodo devuelve un string, la forma de llamarlo sera: string texto; texto = MiMetodo(); Cuando un mtodo devuelve un tipo de dato, es necesario devolverlo con la palabra reservada return, seguido de la variable que contiene el tipo, o un tipo directamente. Ejemplo://Devuelve el valor contenido en strVariable.

return strVariable;//Devuelve un string porque el mtodo donde se encuentra devuelve string.

return texto; La instruccin return tiene que ir al menos en la ltima lnea de cdigo del mtodo. Un mtodo que tiene que devolver un valor y no se le coloca la instruccin return provoca un error. Puede haber mltiples lneas con return dentro del mtodo, pero cuando se ejecuta una, automticamente se sale del mtodo. Es posible que un mtodo que no devuelve un tipo use la instruccin return. En este caso, lo que provoca, es la terminacin de la ejecucin del mtodo. No es necesario darle un valor para devolver. 3. Nombre del Mtodo. En el nombre del mtodo podemos usar cualquier carcter numrico y alfabtico, no recomendndose el uso de otros caracteres (a excepcin del guin bajo) ni acentos. El espacio en blanco est prohibido. 4. Argumentos de entrada. Cuando necesitamos que un mtodo reciba datos para procesarlos internamente, decimos que hay que pasarle argumentos de entrada. Esos argumentos se les conoce comoCaptulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 9

parmetros. Un parmetro es en realidad una variable que se define introduciendo el tipo de dato y el nombre de la variable dentro de los parntesis que van junto al nombre del mtodo. Un mtodo puede tener mltiples parmetros todos ellos separados por comas. Ejemplos: El primer mtodo acepta un parmetro de entrada de tipo int y no devuelve nada(void); el segundo, acepta tres parmetros de entrada: dos de tipo int y uno de tipo string, adems de devolver un valor string. private void Metodo1(int numero) { //Instrucciones } private string Metodo2(int num1, int num2, string texto) { //Instrucciones } Se conoce como firma del mtodo, a la estructura del mtodo, en concreto, a los parmetros de entrada. Aunque se estudiar ms adelante, como parte de la firma del mtodo no se incluye el tipo devuelto para el caso de sobrecarga de mtodos. Por el contrario, si se considera el tipo devuelto para la firma del mtodo en el caso de Delegados (tambin se estudiar ms adelante) 3.2.4.1. Los mtodos estticos. La palabra clave STATIC La palabra reservada static en la declaracin del mtodo, indica que el compilador slo debe de permitir que exista una copia en memoria del mtodo. El mtodo Main(), es un mtodo de tipo static porque sera catastrfico que existieran mltiples puntos de entrada a la aplicacin en memoria. La palabra static va despus del modificador de acceso y antes del tipo de dato que devuelve el mtodo. Ejemplo: private static void Metodo1() Cuando un mtodo es declarado como static, automticamente todo objeto que quiera ser llamado desde el mtodo static tiene que ser declarado de la misma manera. Es decir, si fuera de un mtodo static se quiere definir una variable que ser utilizada por el mtodo, se deber de definir esa variable con la palabra static, con la misma estructura que para el caso del mtodo. Ejemplo: Vamos a definir una variable dentro de la clase, llamada texto, que ser usa por un mtodo del tipo static: private static string Texto;Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 10

Ejemplo de uso de mtodos:class Program { static void Main(string[] args) { string textodevuelto; Datos(); // Llamamos al mtodo Datos para que se ejecute. // Llamamos al mtodo pedir texto y devuelve un valor de Tipo string y lo almacena en la variable textodevuelto. textodevuelto = PedirTexto(); Console.WriteLine("El texto enviado por el mtodo es: " + textodevuelto); Console.ReadLine(); } // Definicin del mtodo llamado Datos que no devuelve ningn valor (tipo void). static private void Datos() { Console.WriteLine("Se est ejecutando el programa..."); Console.WriteLine("Pulse return para continuar..."); Console.ReadLine(); } // Definicin del mtodo llamado PedirTexto, que devuelve un string cuando es llamado. static private string PedirTexto() { Console.Write("Introduce un texto: "); string texto = Console.ReadLine(); return texto; } }

3.2.4.2. Opciones en los parmetros de entrada Hemos visto que en un mtodo su firma est marcada por el tipo y el nmero de parmetros de entrada. En el caso de los parmetros de entrada, existen tres palabras reservadas que nos van a permitir especificar la forma en la que estos parmetros son pasados al mtodo. La palabra clave ref Cuando en un parmetro de entrada lleva la palabra clave ref, significa que ese parmetro se est pasando por referencia y no por valor. El resultado de pasar un parmetro por valor, es que cualquier cambio que se produzca sobre su valor, este es actualizado inmediatamente en el origen una vez que se haya terminado de ejecutar el mtodo. Si el parmetro no es pasado como ref, dispondremos de un valor dentro del mtodo y otro distinto en la llamada.Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 11

Un parmetro que se pasa por referencia tiene que ser inicializado a un valor (para evitarlo se puede usar la palabra reservada out, que se ver ms adelante). En el esquema siguiente se puede observar que si una variable es pasada a un mtodo como parmetro por referencia, al terminar la ejecucin su valor habr cambiado. Si la pasamos por valor no cambiar.

Diferencias entre llamar a un mtodo con un parmetro por valor o por referenciaint Numero = 20; Llama a Metodo sin ref: Metodo(Numero); int Numero = 20; Llama a Metodo con ref: Metodo(ref Numero);

private void Metodo(int Num) { Num = Num * 2; }

private void Metodo(ref int Num) { Num = Num * 2; }

Resultados: Valor de Numero = 20; Valor de Num = 40;

Resultados: Valor de Numero = 40; Valor de Num = 40;

Esquema de diferencias entre un parmetro por valor o por referencia

Como podemos observar, el comportamiento de los parmetros es distinto en el caso de pasarlos por valor o por referencia. Cuando se programa, se debe de decidir cul de las dos opciones es ms beneficiosa para nuestra aplicacin. Notas a ref: Conviene saber que un objeto pasado por referencia ocupa menos espacio en memoria ram que uno que sea pasado por valor (ver grfico ms adelante). Si no queremos que el objeto original cambie sus valores y slo queremos que cambien durante la ejecucin de un mtodo, entonces nuestra solucin sera pasarlo por valor. Como hemos visto, es necesario inicializar los objetos con un valor para poder pasarlos como ref. La palabra ref tiene que ser puesta cada vez que un parmetro tiene que ser pasado por referencia. En un mtodo pueden convivir parmetros con ref y parmetros sin ref.Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 12

Si el objetivo final de pasar un objeto a un mtodo es cambiar su valor, lo razonable sera hacerlo por referencia para evitar copias innecesarias del objeto en memoria, tal y como se puede ver en el siguiente esquema:Diferencias en la gestin de la memoria al pasar a un mtodo un parmetro por valor o por referenciaint [ ] Numeros = new int[ 5 ]; Llama a Metodo sin ref: Metodo(Numeros); Se realiza una copia exacta del objeto en memoriaMatriz NUMEROSReferencias Valores

Matriz METODOReferencias Valores

0 1 2 3 4

AA2C 1472 16DE BC74 FB12

21 2 10 24 15Valores en la memoria

0 1 2 3 4

AA2C 1472 16DE BC74 FB12

21 2 10 24 15Valores en la memoria

Direcciones de memoria en Hexadecimal

Direcciones de memoria en Hexadecimal

int [ ] Numeros = new int[ 5 ]; Llama a Metodo con ref: Metodo(ref Numeros); Se realiza una copia en memoria pero slo de las referenciasMatriz NUMEROSReferencias Valores

Matriz METODOReferencias

0 1 2 3 4

AA2C 1472 16DE BC74 FB12

21 2 10 24 15Valores en la memoria

0 1 2 3 4

AA2C 1472 16DE BC74 FB12

Direcciones de memoria en Hexadecimal

Direcciones de memoria en Hexadecimal

3.2.4.3. La palabra clave OUT Su objetivo es idntico a ref, es decir, pasar parmetros por referencia en lugar de por valor. La diferencia radica en que out no obliga a inicializar los valores de las variables que son pasadas a los mtodos.Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 13

Al igual que ref, un parmetro puesto como out exige que tanto el mtodo como la llamada tengan la palabra out. Ejemplo: static void Main(string [ ] args) { string MiTexto = Texto de Prueba; Metodo(out MiTexto); } private static void Metodo(out string Texto) { Texto = Nuevo Texto de Prueba; } Ejemplo de pasar una matriz a un mtodo para que sea inicializada por el mtodo. Usaremos la palabra out en lugar de ref, ya que ref nos obligara a inicializarla antes de enviarla:public partial class Principal : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { // Declaramos la matriz pero no la inicializamos con // valores. string[] Matriz; // Enviamos la matriz al mtodo para que sea incializada. // Usamos la palabra clave out para que no de error. DarValorMatriz(out Matriz); // Mostramos los datos que ha rellenado el mtodo en la // matriz Console.WriteLine("Los elementos en la matriz son:"); foreach (string Dato in Matriz) lblVer.Text = Dato + ; } private static void DarValorMatriz(out string[] arr) { // Damos valores a la matriz arr = new string[6] {"Luis", "Pedro", "Luca", "Antonio", "Mara", "Marcos"}; } }

Si bien no es necesario inicializar la variable para pasarla al mtodo usando la palabra out, una vez dentro del mtodo debe, obviamente, tomar un valor antes de devolverla. 3.2.4.4. La palabra clave PARAMS Hasta ahora, todos los mtodos, exigen que los parmetros de entrada deban de ser enviados obligatoriamente. Es decir, no podemos hacer unaCaptulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 14

llamada a un mtodo, en la cual, nos falta rellenar algn parmetro. En el caso de necesitar un mtodo que disponga de parmetros variables, usaremos la palabra clave params. Ejemplo: private void Metodo(params string [ ] ListaParametros) { foreach(string Parametro in ListaParamentros) lblVer.Text = Valor del Parametro: + Parametro; } No se permiten parmetros adicionales despus de la palabra clave params, ni tampoco la existencia de varios params. 3.2.4.5. Mtodos sobrecargados Los mtodos sobrecargados son cuando varios mtodos se llaman igual, pero tienen distintos argumentos de entrada, es decir, es como tener distintas versiones del mismo mtodo. La sobrecarga de mtodos obliga a que los parmetros de entrada sean diferentes, sin importar el tipo devuelto. Por ejemplo, un mtodo void y un mtodo que devuelve un string, si no hay ms cambios en la firma del mtodo, al compilar, dar un error. Ejemplo: private void MiMetodo(string Texto) { // Instrucciones } private void MiMetodo(int Numero) { // Instrucciones } En este ejemplo, MiMetodo, dispone de dos versiones: la primera admite un string y, la segunda, un int. Esto es a lo que se conoce como sobrecarga de mtodos. Ejemplo de sobrecarga de mtodos:public partial class Principal : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { string[] MatrizNombres; int[] MatrizNumeros; DarValorMatriz(out MatrizNombres); DarValorMatriz(out MatrizNumeros); }

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 15

//Primera versin del mtodo DarValorMatriz que admite una matriz string private static void DarValorMatriz(out string[] arr) { // Damos valores a la matriz de tipo string arr = new string[6] {"Luis", "Pedro", "Luca", "Antonio", "Mara", "Marcos"}; } //Segunda versin del mtodo DarValorMatriz que admite una matriz int private static void DarValorMatriz(out int[] arr) { // Damos valores a la matriz de tipo int arr = new int [] { 1, 4, 21, 2, 24, 3 }; } }

En este ejemplo, como se puede ver, al llamar al mtodo DarValorMatriz, la primera llamada, DarValorMatriz(out MatrizNombres), llama y ejecuta el mtodo que es string. En la segunda, DarValorMatriz(out MatrizNumeros), llama al mtodo que es int. Estas asignaciones, o elecciones del mtodo a ejecutar las hace NetFramework por si slo sin necesidad de especificrselo. Esto es posible porque comprueba la firma del mtodo en la invocacin y lo ajusta a la firma correcta. Este es el motivo por el cual no puede haber dos mtodos con el mismo nombre e idntica firma de parmetros de entrada, ya que no sabra a cual asignar. Notas a la sobrecarga de mtodos: Puede haber tantos mtodos sobrecargados como se desee. No existe lmite. Los modificadores ref y out son tratados en ejecucin de forma diferente, pero en compilacin se tratan de la misma forma, lo que significa que no podemos definir dos firmas iguales de parmetros de entrada en las que slo cambia la palabra ref o out. Por ejemplo la siguiente definicin de mtodos sobrecargados dara el siguiente error en la compilacin: no se puede definir mtodos de sobrecarga que difieran slo en ref y out. private void MiMetodo(out string Nombre) private void MiMetodo(ref string Nombre) Si slo cambiamos el parmetro de salida, es decir void o el tipo devuelto, no se considera sobrecarga y dara un error de compilacin. La siguiente definicin dara el siguiente error en la compilacin: ya define un miembro denominado 'MiMetodo' con los mismos tipos de parmetros. private int MiMetodo(string Nombre) private void MiMetodo(string Nombre)Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 16

Ms adelante en este mismo captulo, es estudiar los modificadores abstract y sealed.

3.2.5. Qu es un constructor de la clase? Cuando queremos instanciar la clase utilizamos el operador new: Flan Vainilla = new Flan(); El constructor de la clase es activado en ese momento y permite que se cree el objeto del tipo de la clase. Esto es posible porque existe un mtodo especial llamado el constructor de la clase que se ejecuta una vez hemos utilizado el operador new. Este mtodo se identifica porque es el nico que se llama igual que la clase. Es decir, si la clase se llama Flan su constructor ser: public Flan() { } Si el programador no disea un mtodo constructor de la clase, .NET crea por omisin un constructor sin parmetros, cuya nica funcin es crear la clase. En el constructor podemos hacer las mismas cosas que se hacen en cualquier mtodo. Normalmente se suele usar para inicializar los atributos de la clase que se usarn desde las propiedades, o para realizar operaciones previas a la creacin del objeto. Cuando creamos un constructor, sustituye automticamente al constructor por defecto. Los mtodos constructores permiten la sobrecarga, es decir, puede haber ms de un constructor de la clase (todos con el mismo nombre y distintos parmetros).

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 17

3.2.6. Constructores estticos. Un constructor esttico se utiliza para inicializar cualquier dato esttico o realizar operaciones que slo se harn una vez. Es llamado automticamente antes de crear la primera instancia o de hacer referencia a cualquier miembro esttico. Ejemplo:class ConstructorEstatico { //Esta variable debe de ser inicializada la primera vez que se //llame a la clase. Es una variable de slo lectura. static readonly DateTime HoraOperacion; //Constructor esttico que dar valor a la variable la primera //vez. Se ejecuta antes de que se cree la primera instancia o se //acceda a cualquier miembro. static ConstructorEstatico() { HoraOperacion = DateTime.Now; } }

Un constructor esttico tiene las siguientes caractersticas: No tiene modificadores de acceso ni admite parmetros. Se llama de forma automtica para iniciar la clase antes de crear la primera instancia o de hacer referencia a cualquier miembro esttico. El constructor esttico no puede ser llamado directamente. El usuario no puede controlar cuando se ejecuta el constructor esttico en el programa. Los constructores estticos se utilizan normalmente cuando la clase hace uso de un archivo de registro y el constructor escribe entradas en dicho archivo. Ver ejemplo: Uso ConstructoresEstaticos 3.2.7. Qu es un destructor de la clase? En el proceso de creacin del objeto del tipo de la clase, .NET asigna la cantidad de memoria necesaria para su manejo. Si no hay suficiente memoria, se lanza un mensaje del tipo: System.OutOfMemoryException. NET se encarga de liberalizar la memoria cuando ya no se necesita el objeto que se cre mediante el Garbage Collector (GC) (se ver ms adelante su funcionamiento). Esto ocurre en el momento en el que un objeto que se ha definido dentro de un mbito concreto deja de tener validez al termina de ejecutarse ese mbito. Por ejemplo, una variable de un bucle for, cuando termina el bucle (fin de mbito), entonces el Garbage Collector se encarga de limpiar la memoria que ocupaba esa variable y todos los objetos definidos dentro de ese bucle.Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 18

Antes de su destruccin permite invocar a un mtodo destructor, que nos permitir, por ejemplo, guardar informacin sobre estado de objetos, memoria, limpieza de objetos, cierre de conexiones, etc. El mtodo destructor llamar automticamente al mtodo Finalize de la clase Object (se ver ms adelante su funcionamiento). Slo puede haber un mtodo destructor por clase y es invocado automticamente. Antes de que un objeto sea destruido, .NET llama al mtodo destructor de la clase, si lo hubiera, para realizar las operaciones que el mtodo destructor tiene implementadas, como puede ser, cerrar una conexin a base de datos. Para aadirle un mtodo destructor a la clase, usaremos el smbolo ~ (alt + 126), seguido del nombre de la clase. Ejemplo: ~Flan() { // Cdigo a ejecutar. } Una clase slo puede tener un destructor. No permite modificadores de acceso ni tiene parmetros, adems no permite la sobrecarga. No se le puede llamar explcitamente, porque se hace de forma automtica por el CLR. Ver el ejemplo: Uso DestructorWin. 3.2.8. La gestin de la memoria. El Garbage Collector. Un Garbage Collector es un sistema implcito de gestin de la memoria que implementan algunos lenguajes de programacin de tipo interpretado o semi-interpretado, como son los que hay en .Net o Java. El sistema operativo pone a disposicin de los programas una cantidad de memoria, para que estos gestionen esta memoria con las siguientes caractersticas: De la memoria asignada, deben de hacer una reserva de espacios para uso del programa y los datos que contiene. Tienen que encargarse de liberar los espacios de memoria que fueran previamente reservados y ya no se necesitan. Adems, una vez liberados ciertos espacios de memoria, puede que queden espacios en blanco (memoria sin usar), entre el resto de los datos que s se estn usando y, por tanto, ha de compactar estos espacios para hacerlos consecutivos entre s (eliminado los espacios en blanco).

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 19

Y por ltimo, controlar que espacios de la memoria asignada por el sistema operativo para el programa estn libres y cules no. El Garbage Collector (Recolector de Basura) es el encargado de limpiar los objetos que ya no se usan. Su funcionamiento es arbitrario y se tiene poco control sobre el momento exacto en el que se elimina el objeto, tal y como se puede observar en el ejemplo: Uso DestructorWin. Cuando un lenguaje dispone de recoleccin de basura, el programador no tiene que encargarse de la reserva de memoria, ya que este proceso es realizado por el Garbage Collector. Cada vez que declaramos un objeto en nuestro programa, se asigna de forma automtica una cantidad de memoria. Esta cantidad, en principio, no la conocemos ni la manejamos. Cuando se compila el programa automticamente se incluye en ste una subrutina que corresponde al recolector de basura. Esta subrutina tambin es invocada peridicamente sin la intervencin del programador.Esquema del Limpieza y Compactacin del Garbage Collector El Garbage Collector verifica y asigna espacios de memoria Objeto A Objeto B

Objeto C Objeto D Objeto E

El Garbage Collector limpia el Objeto B Objeto A Objeto C Objeto D Objeto E

El Garbage Collector compacta la memoria Objeto A Objeto C

Objeto D Objeto E

El recolector de basura es informado de todas las reservas de memoria que se producen en el programa. Adems, el compilador colabora para que Memoria sin usar sea posible llevar una cuenta de todas las referencias que existen a un determinado espacio de memoria reservado. EL CLR de .Net exige que todos los recursos deban de asignarse a un concepto llamado memoria administrada, conocido como Heap. El heap no es ms que una zona reservada de memoria para ir guardando los objetos y datos que nuestra aplicacin va a usar. El CLR, por mediacin de Garbage Collector, se encarga de hacer reservas de espacio para nuestros objetos y eliminar esas reservas de espacio cuando el objeto ya no se usa. Esto es un proceso automtico, que evita los problemas que se dan en otros lenguajes, donde puede ocurrir que intentemos acceder a un recurso que no se le asigno memoria, o a un recurso que por causas desconocidas ya no est disponible. El proceso automtico de recoleccin de basura (termino que se aplica a objetos que ya no se usan), est basado en algoritmos optimizados para su uso en distintos escenarios, con el fin de obtener el mejor rendimiento en cada momento.Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 20

Su funcionamiento se realiza por mediacin de un puntero, que controlan si existe espacio suficiente para almacenar el objeto en la zona reservada. Cuando instanciamos una clase con el operador new, automticamente, el CLR, verifica que existe espacio disponible entre el puntero y el espacio total de memoria reservada. Si existe, coloca el objeto y desplaza el puntero al final de la reserva de memoria del nuevo objeto, tal y como podemos ver en el siguiente grfico. Si no dispone de memoria, realiza una recoleccin por mediacin del mtodo Collect, que veremos ms adelante.Esquema del Heap o Memoria AdministradaMemoria Administrada Intentamos instanciar el objeto D, el CLR verifica que hay espacio disponible para su tamao entre el puntero y el final de memoria reservada. Si hay espacio, lo coloca, en caso contrario hace un Collect. Memoria Administrada

Memoria Reservada para la aplicacin, pero libre de asignacinPosicin del Puntero Objeto C

Memoria Reservada

Posicin del Puntero

Objeto D

Objeto C ClaseD obj = new ClaseD();

Las clases, cuando son instanciadas con el operador new, son localizadas por mediacin del CLR en el montn administrado.

Objeto B

Objeto B

Objeto A

Objeto A

Las recolecciones se efectan cuando es necesaria ms memoria, o cuando pasa un tiempo concreto. Las recolecciones, efectuadas por el mtodo Collect de la clase GC, se basan en un concepto llamado Generaciones, que consiste en crear los objetos en nmeros concreto de generaciones, de tal forma, que los objetos son clasificados por su antigedad de creacin. Una generacin es una unidad de medida de la edad relativa de los objetos en la memoria. El nmero de generacin o la edad de un objeto indica la generacin a la que pertenece. Los objetos creados ms recientemente forman parte de las ltimas generaciones y tienen nmeros de generacin ms bajos que los objetos creados en fases anteriores del perodo de duracin de la aplicacin. Los objetos de la generacin ms reciente pertenecen a la generacin cero. En realidad, las generaciones son mecanismos aplicados por el Garbage Collector para mejorar el rendimiento del uso de memoria y, por extensin, nuestra aplicacin. La finalidad es que los objetos creados ms recientemente, formen parte de generaciones nuevas, mientras que los creados al principio, formen parte de generaciones antiguas. El GC realiza tareas de limpieza de la memoria por el nmero de generacin, en lugar de hacerlo para todo la memoria administrada, que sera una prdida de tiempo innecesaria. Siempre empiezaCaptulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 21

limpiando las generaciones antiguas, aunque existe la posibilidad de hacer una limpieza a una generacin concreta. Si a pesar de hacer recolecciones, an no ha sido posible liberar memoria suficiente para colocar el nuevo objeto, el sistema notifica una excepcin del tipo: OutOfMemoryException. 3.2.8.1. Cmo sabe el Garbage Collector que un objeto no se usa? El Garbage Collector, como explicamos anteriormente, limpia de la memoria todos aquellos objetos que ya han dejado de tener utilidad para la aplicacin. El conocer que un objeto est libre para su destruccin es posible gracias a un concepto llamado races (roots). Toda aplicacin tiene un conjunto de races que apuntan a los objetos que se encuentran en el Heap. Por ejemplo, todas las referencias globales y estticas que apuntan a la memoria administrada; cualquier variable local con punteros a objetos de la pila de subprocesos; registros de la CPU que apuntan tambin a objetos del Heap, forman parte de las races de la aplicacin. Todas las races activas son mantenidas por el compilador Just-In-Time(JIT) y el CLR, hacindolas accesibles a los algoritmos de limpieza del Garbage Collector. El Garbage Collector inspecciona todas las races mirando no slo a que objeto apuntan, sino tambin si ese objeto apunta a su vez a otro objeto de la memoria administrada. AL final, acaba obteniendo una grfica de que objetos estn relacionados con quien y cual est activo y cual no. Ver el siguiente esquema.

Esquema de Races (roots) dentro del Garbage CollectorAplicacinRAICES (roots)

HeapMemoria ReservadaLimpieza de objetosObjeto H Objeto G Objeto F Objeto E

AplicacinRAICES (roots)

Heap

Globales y Estticas

Globales y Estticas

Memoria Reservada

Objeto G Locales Objeto E Objeto D Registros CPU Objeto B Objeto A

Locales

Objeto D Objeto C

Registros CPU

Objeto B Objeto A

Toda raz activa tiene un puntero al objeto dentro del Heap. Un objeto pude apuntar a otro objeto dentro del Heap, como el objeto D al objeto G. Esto tambin se considera una raz activa. Si no hay una raz se considera basura por parte del GC.

Un objeto que despus de recorrer las races no ha sido localizado por ninguna, es un objeto que ya no se usa y por tanto puede ser recolectado en elCaptulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 22

siguiente Collect, es lo que se llama un objeto basura. El recolector va recorriendo los objetos de forma recursiva. 3.2.8.2. La Clase GC, el Garbage Collector de .Net Dentro del espacio de nombres System, existe la clase GC. Esta clase es el Garbage Collector de .Net. El Recolector no se ejecuta como parte de nuestra aplicacin, sino que es un proceso aadido a la misma que consume recursos. Por tanto, Microsoft recomienda que su uso sea realizado de forma automtica y que no se fuerce su ejecucin. A pesar de esto, si uno quiere trabajar directamente sobre el Garbage Collector y manipularlo, existe la clase GC, que incluye ciertos mtodos para su manejo. Los mtodos de esta clase influyen en el momento en que se realiza la recoleccin de elementos no utilizados de un objeto y en el momento en que se liberan los recursos asignados por un objeto. Las propiedades de esta clase proporcionan informacin sobre la cantidad de memoria total disponible en el sistema y la categora de edad, o generacin, de la memoria asignada a un objeto. El recolector de elementos no utilizados realiza un seguimiento de los objetos asignados en la memoria administrada, y los reclama. De forma peridica, el recolector de elementos no utilizados reclama la memoria asignada a los objetos para los que no existen referencias vlidas (las races de la aplicacin, o referencias entre objetos). La recoleccin de elementos no utilizados se produce de forma automtica, cuando una solicitud de memoria no puede satisfacerse utilizando la memoria libre que queda disponible. Una aplicacin tambin puede provocar la recoleccin de elementos no utilizados mediante el mtodo Collect. La recoleccin de elementos no utilizados consta de los siguientes pasos: El recolector de elementos no utilizados busca los objetos administrados a los que se hace referencia en el cdigo administrado. El recolector de elementos no utilizados intenta finalizar los objetos a los que no se hace referencia. El recolector de elementos no utilizados libera los objetos a los que no se hace referencia y reclama la memoria utilizada por estos objetos. Durante la recoleccin de elementos no utilizados, el recolector no liberar un objeto si encuentra una o varias referencias al mismo en el cdigo administrado. El recolector de elementos no utilizados no reconoce, sinCaptulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 23

embargo, las referencias a objetos desde el cdigo no administrado y puede liberar objetos que se estn utilizando exclusivamente en cdigo no administrado, a menos que se le impida hacerlo de forma explcita. El mtodo KeepAlive proporciona un mecanismo que impide que el recolector de elementos no utilizados recoja objetos que an estn en uso en el cdigo no administrado. Salvo en el caso de las asignaciones de memoria administrada, las implementaciones del recolector de elementos no utilizados no incluyen informacin sobre los recursos mantenidos por un objeto, como los identificadores de archivo o las conexiones de base de datos. Cuando un tipo utiliza recursos no administrados que deben liberarse antes de que se reclamen las instancias del tipo, ste puede implementar un finalizador. En la mayora de los casos, los finalizadores se implementan reemplazando el mtodo Finalize; no obstante, los tipos escritos en C# o C++ implementan destructores (vistos anteriormente), que los compiladores convierten en un reemplazo del mtodo Finalize. En la mayora de los casos, si un objeto tiene un finalizador, el recolector de elementos no utilizados llama a dicho finalizador antes de liberar el objeto. Sin embargo, el recolector de elementos no utilizados no debe llamar a los finalizadores en todas las situaciones; por ejemplo, el mtodo SuppressFinalize evita explcitamente que se llame a un finalizador. Adems, el recolector de elementos no utilizados no tiene por qu utilizar un subproceso especfico para finalizar objetos ni tampoco tiene por qu garantizar el orden en que se llama a los finalizadores para objetos que se hacen referencia mutuamente pero que sin embargo estn disponibles para su recoleccin. En los escenarios en los que los recursos deben liberarse en un momento determinado, las clases pueden implementar la interfaz IDisposable, que contiene el mtodo Dispose que realiza tareas de administracin y limpieza de recursos. Las clases que implementan Dispose deben especificar, como parte de su contrato de clase, si los consumidores de la clase van a llamar al mtodo para limpiar el objeto y cundo van a hacerlo. El recolector de elementos no utilizados no llama al mtodo Dispose de forma predeterminada; sin embargo, las implementaciones del mtodo Dispose pueden llamar a los mtodos de la clase GC para personalizar el comportamiento de finalizacin del recolector. Aunque no es obligatorio, se recomienda que los recolectores de elementos no utilizados admitan la caducidad de objetos mediante el uso de generaciones. Una generacin es una unidad de medida de la edad relativa de los objetos en la memoria. El nmero de generacin o la edad de un objeto indica la generacin a la que pertenece. Los objetos creados ms recientemente forman parte de las ltimas generaciones y tienen nmeros deCaptulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 24

generacin ms bajos que los objetos creados en fases anteriores del perodo de duracin de la aplicacin. Los objetos de la generacin ms reciente pertenecen a la generacin cero. Mtodos usuales de la clase esttica GC (Garbage Collector): Collect(). Fuerza al recolector a ejecutarse limpiando los objetos no usados y compactando la memoria. Si se quiere hacer un uso de este mtodo, podra ser una idea hacerlo antes de asignar memoria para un objeto, es decir, antes de instanciarlo. CollectionCount(int). Devuelve el nmero de veces que se ha producido una recoleccin. Si implementamos nuestra propia administracin de recursos, es posible que se necesite forzar la recoleccin de elementos no utilizados peridicamente llamando al mtodo Collect. Dado que sta es una operacin costosa, se puede mejorar el rendimiento si se omite la llamada cuando se ha producido recientemente una recoleccin de elementos no utilizados. Para conseguirlo, hay que guardar el valor devuelto por CollectionCount justo despus de llamar a Collect. La prxima vez que se necesite llamar a Collect, se compara el valor actual devuelto por CollectionCount y el valor guardado. Si los dos valores son iguales significa que no se ha producido ninguna recoleccin en ese perodo de tiempo y sera razonable volver a llamar a Collect. Se puede ver un ejemplo de todo esto en Uso de GarbageCollector. GetGeneration(object). Especificando un objeto, nos devuelve el nmero de generacin en la que se encuentra. GetTotalMemory(bool). Permite conocer la memoria total asignada en bytes. Si se pone true en la llamada al mtodo, entonces esperar a recolectar los objetos inutilizados para dar el valor de la memoria. En caso de false, devuelve la cantidad de bytes ocupados sin hacer una recoleccin de objetos previa. KeepAlive(objeto). La finalidad del mtodo KeepAlive es garantizar la existencia de una referencia a un objeto que tenga probabilidades de ser reclamado prematuramente por el recolector de elementos no utilizados. Un escenario comn en el que podra darse esta situacin es cuando no existen referencias al objeto en el cdigo administrado o en los datos, pero el objeto todava se utiliza en el cdigo no administrado, como en las API Win32, las DLL no administradas o los mtodos que utilizan COM. SuppressFinalize(objeto). Solicita al sistema que no llame al finalizador del objeto seleccionado.

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 25

Propiedades para GC MaxGeneration. Devuelve el nmero mximo de generaciones que admite en ese momento el sistema. El nmero de generacin o la edad es una medida relativa a duracin de un objeto que se define en la implementacin. Los objetos creados ms recientemente pertenecen a la generacin cero y los objetos ms antiguos pertenecen a una generacin menor o igual a la generacin devuelta por la propiedad MaxGeneration. El recolector de elementos no utilizados asume que la memoria ms nueva tiene ms posibilidades de ser elegida para la recoleccin de elementos no utilizados que la memoria ms antigua. Por lo tanto, el recolector de elementos no utilizados mejora su rendimiento ajustando los nmeros de generacin cada vez que reclama memoria, y el valor de la propiedad MaxGeneration puede aumentar con el tiempo. Si se implementa la edad de los objetos, la propiedad MaxGeneration devuelve el nmero de generacin mximo utilizado por el sistema; en caso contrario, esta propiedad devuelve cero. Para esta implementacin, se garantiza que el valor devuelto por la propiedad MaxGeneration se va a mantener constante durante el perodo de duracin de una aplicacin en ejecucin. Esta propiedad se utiliza para determinar el valor mximo que puede especificarse al llamar al mtodo Collect cuando toma un parmetro de generacin. 3.2.8.3. El mtodo Object.Finalize() Este mtodo se invoca de forma automtica cuando un objeto pase a ser inaccesible, salvo que previamente y mediante el mtodo SuppressFinalize de la clase GC, haya sido excluido del proceso de finalizacin. Slo se realiza una llamada al mtodo Finalize para una instancia especfica, a menos que el objeto vuelva a registrarse mediante un mecanismo como ReRegisterForFinalize y no se haya llamado posteriormente a SuppressFinalize. Cualquier implementacin de Finalize en un tipo derivado (herencia), deben llamar a la correspondiente implementacin de tipo base de Finalize.Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 26

Este es el nico caso en el que se permite al cdigo de la aplicacin llamar a Finalize. Las operaciones de Finalize tienen las siguientes limitaciones: El momento exacto en que se ejecuta el finalizador durante la recoleccin de elementos no utilizados no est definido. No se garantiza la liberacin de recursos en un momento concreto, a menos que se llame a un mtodo Close o a un mtodo Dispose. No se garantiza que los finalizadores de dos objetos se ejecuten en un orden determinado, aunque un objeto haga referencia al otro. Es decir, si el objeto A hace referencia al objeto B y ambos tienen finalizadores, puede que el objeto B ya haya terminado cuando se inicie el finalizador del objeto A. No se ha especificado el subproceso en el que se ejecuta el finalizador. Puede que el mtodo Finalize no se ejecute hasta su finalizacin o puede que no llegue a ejecutarse en las siguientes circunstancias excepcionales: Otro finalizador se ha bloqueado de forma indefinida (entra en un bucle infinito, intenta obtener un bloqueo que nunca puede conseguir, etc.). Como el motor en tiempo de ejecucin intenta ejecutar los finalizadores hasta su terminacin, puede que no se llame a otros finalizadores si un finalizador se bloquea de forma indefinida. El proceso termina sin que el motor en tiempo de ejecucin pueda efectuar una limpieza. En este caso, la primera notificacin de terminacin del proceso por parte del motor en tiempo de ejecucin es una notificacin DLL_PROCESS_DETACH. Finalize puede llevar a cabo cualquier accin, como el restablecimiento de un objeto (es decir, hacer que el objeto vuelva a ser accesible, tambin conocido como revivir) despus de su limpieza durante la recoleccin de elementos no utilizados. Sin embargo, el objeto slo puede restablecerse una vez; no se puede llamar a Finalize en objetos restablecidos durante la recoleccin de elementos no utilizados. Los destructores de la clase son el mecanismo de C# para realizar operaciones de limpieza. Proporcionan mecanismos de proteccin apropiados, como la llamada automtica al destructor de tipo base. De todas formas, un tipo debe implementar Finalize cuando utiliza recursos no administrados, como identificadores de archivo o conexiones de base de datos que deben liberarse cuando se reclama el objeto administrado que los utiliza. Por mediacin del mtodo Dipose de la clase IDisposable, podemos tener un medio complementario y ms controlable de eliminar recursos.Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 27

3.2.8.4. El mtodo IDisposable.Dispose() Este mtodo se utiliza para cerrar o liberar recursos no administrados como son archivos, secuencias e identificadores que una instancia mantiene de la clase que implementa esta interfaz. El objetivo es liberar todos los recursos de un objeto o todas las tareas relacionadas con la preparacin de un objeto para que este vuelva a utilizarse. Cuando realizamos una implementacin del mtodo Dispose() en nuestra clase, debemos de asegurarnos que se liberan todos los recursos utilizados mediante la propagacin de la llamada a travs de la jerarqua de contencin. Por ejemplo, Si el Objeto A, llama al objeto B y este al objeto C, en ese caso, la implementacin del Dispose de A debe llamar al Dispose de B y este a su vez al Dispose de C. Si se implementa la interfaz IDisposable, adems, el mtodo Dispose de la clase debe de llamar al mtodo Dispose de la clase Base. Igualmente, debemos de controlar en la implementacin del mtodo Dispose, que slo se le llama una vez, descartando todas las llamadas que se realicen al mtodo, despus de la primera. Si llamamos varias veces al mtodo Dispose, este realizar una excepcin del tipo ObjectDisposeException, debido a que ya se han desechado los recursos. Como debe llamarse al mtodo Dispose de forma explcita, los objetos que implementan IDisposable tambin deben implementar un finalizador para controlar la liberacin de los recursos cuando no se llama a Dispose. De forma predeterminada, el recolector de elementos no utilizados llama automticamente al finalizador de un objeto antes de reclamar su memoria. Sin embargo, una vez que se ha llamado al mtodo Dispose, no suele ser necesario que el recolector de elementos no utilizados llame al finalizador del objeto desechado. Para evitar una finalizacin automtica, las implementaciones de Dispose pueden llamar al mtodo SuppressFinalize, del Garbage Collector. 3.2.9. Las Partial Class Una clase parcial, o Partial Class, es una clase que est definida en varias declaraciones de clases con el mismo nombre, pero todas con la palabra partial por delante y ubicadas en el mismo espacio de nombres, o espacio de tipo. A la hora de la compilacin, todas las partial son fusionadas en una. Sola clase. Ejemplo de declaracin de una clase partial: public partial class ClaseA

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 28

3.3. Las EstructurasLas estructuras son similares a las clases en que pueden representar estructuras de datos que pueden contener miembros de datos y miembros de funcin. No obstante, a diferencia de las clases, las estructuras son tipos de valores y no requieren asignacin del montn. Una variable de un tipo de estructura contiene directamente los datos de la estructura, mientras que una variable de un tipo de clase contiene una referencia a los datos, que se conocer posteriormente como objeto. Las estructuras son particularmente tiles para estructuras de datos pequeas que tienen semnticas de valor. Los nmeros complejos, los puntos de un sistema de coordenadas o los pares de valores clave de un diccionario son buenos ejemplos de estructuras. La clave de estas estructuras de datos es que tienen pocos miembros de datos, que no necesitan utilizar herencia o identidad referencial y que pueden ser implementadas convenientemente utilizando semnticas de valor donde la asignacin copia el valor en lugar de la referencia. Definicin de una estructura: public struct PostalAddress { Implementacin de campos, propiedades, mtodos y eventos. } Toda estructura, al igual que las clases tiene un modificador de acceso, que en este caso, puede ser solamente: Public, Internal o Private. Los modificadores Protected y Protected Internal, no son aplicables dado que las estructuras a diferencia de las clases, no permiten herencia. A continuacin del modificador de acceso lleva la palabra reservada struct, que indica que este fragmento de cdigo es una estructura. Por ltimo el nombre de la estructura, que mantiene las mismas condiciones que para una clase, no se puede utilizar espacios en blanco ni algunos caracteres especiales. El modificador partial, al igual que en las clases, indica que esa declaracin de estructura es una declaracin de tipo parcial. Lo que significa que puede haber ms implementaciones de estructuras con el mismo nombre dentro del mismo espacio de nombres, pero todas con la palabra partial por delante. A la hora de la compilacin, todas las estructuras partial son fusionadas en una sola.

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 29

Aunque no pueden heredar ni de clases, ni de otras estructuras, si que pueden implementar interfaces. Ejemplo de uso de estructuras: Uso Estructuras.public struct CoOrds { public int x, y; public CoOrds(int p1, int p2) { //Si no se pasan valores en la llamada al //constructor. //Pone valores por defecto para el tipo. x = p1; y = p2; } } class Program { static void Main(string[] args) { // Inicializa los valores: CoOrds coords1 = new CoOrds(); CoOrds coords2 = new CoOrds(10, 10); // Muestra el resultado: Console.Write("CoOrds 1: "); Console.WriteLine("x = {0}, y = {1}", coords1.x, coords1.y); Console.Write("CoOrds 2: "); Console.WriteLine("x = {0}, y = {1}", coords2.x, coords2.y); } }

3.3.1. Diferencias entre Clases y Estructuras Casi todas las estructuras comparten la misma sintaxis que las clases, aunque estn ms limitadas que stas: Dentro de una declaracin de estructura, los campos no se pueden inicializar a menos que se declaren como constantes o estticos. Una estructura no puede declarar un constructor predeterminado (es decir, un constructor sin parmetros) ni un destructor. Las estructuras no pueden heredar de clases u otras estructuras. Las estructuras se copian en la asignacin. Cuando se asigna una estructura a una nueva variable, se copian todos los datos, y cualquier modificacin que se realice en la nueva copia no afecta a los datos de la copia original. Las estructuras son tipos de valor y las clases son tipos de referencia.Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 30

A diferencia de las clases, se pueden crear instancias de las estructuras sin utilizar un operador new. Las estructuras pueden declarar constructores que tienen parmetros. Una estructura no puede heredar de otra estructura o clase, ni puede ser la base de una clase. Todas las estructuras heredan directamente de System.ValueType, que hereda de System.Object. Una estructura puede implementar interfaces. Una estructura se puede utilizar como tipo que acepta valores null y se le puede asignar un valor null. Los tipos de estructura nunca son abstractos y son siempre sellados implcitamente. Por lo tanto, los modificadores abstract y sealed no estn permitidos en una declaracin de estructura. Debido a que las estructuras no permiten la herencia, la accesibilidad declarada de un miembro de estructura no puede ser protected ni protected internal. Los miembros de funcin de una estructura no pueden ser abstract ni virtual, y slo se permite el modificador override para invalidar mtodos heredados de System.ValueType. La asignacin a una variable de un tipo struct crea una copia del valor que se asigne. Esto difiere de la asignacin a una variable de un tipo de clase, que copia la referencia pero no el objeto identificado por la referencia. De forma similar a una asignacin, cuando se pasa una estructura como parmetro de valor o se devuelve como resultado de un miembro de funcin, se crea una copia de la estructura. Una estructura se puede pasar por referencia a un miembro de funcin utilizando un parmetro ref u out. Cuando una propiedad o un indizador de una estructura es el destino de una asignacin, la expresin de instancia asociada con el acceso a la propiedad o indizador debe estar clasificada como una variable. Si la expresin de instancia est clasificada como un valor, se produce un error de compilacin En cuanto a los constructores estticos (static) para estructuras, siguen la mayora de las mismas reglas que las clases. La ejecucin de un constructor esttico para un tipo struct la desencadena el primero de los siguientes eventos que se produzcan en un dominio de aplicacin: Se hace referencia a un miembro de instancia del tipo struct. Se hace referencia a un miembro esttico del tipo struct. Se llama a un constructor explcitamente declarado del tipo struct.

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 31

3.4. La Herencia de clasesLa herencia es una de las cualidades ms importantes de la Programacin Orientada a Objetos (POO), porque permite que una clase herede todas las caractersticas definidas en la clase base, o la clase de la que hereda. Lo nico que no se puede heredar son los mtodos constructores y los destructores. La herencia se realiza a travs de una derivacin, lo que significa que una clase se declara utilizando una clase base de la cual hereda los datos y el comportamiento. Para declarar una herencia, debemos de colocar dos puntos en el nombre de la class que estamos definiendo y, a continuacin el nombre de la clase base, o clase de la que hereda. Ejemplo: Class Empleado : EmpleadoBase { //Atributos, propiedades y mtodos. } En este ejemplo, la clase empleado hereda de EmpleadoBase. Todas las clases mantiene una estructura jerrquica. Toda clase pertenece siempre a una clase superior o superclase (se conoce con el nombre de clase base). Una clase puede contener una o varias subclases, tambin llamadas clases derivadas. Existe una clase llamada Object, que es la clase raz de toda la jerarqua de clases de la biblioteca .NET. Por tanto, todas las clases que diseemos, pertenecern en ltima instancia a la clase Object. En C#, a diferencia de C++, la herencia es simple, es decir, slo puede heredar de una clase a la vez. Sin embargo, dado que una clase base puede a su vez heredar de otra clase, tenemos que una clase puede en realidad heredar de varias. Ver los siguientes esquemas:

Super Clase Object

Clase EmpleadoBase

Clase Empleado

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 32

El siguiente esquema muestra como los distintos, atributos propiedades y mtodos de una clase son pasados a la siguiente por mediacin de la herencia:Esquema de la Herencia entre clasesObject : EmpleadoBase Super Class Object Equals() GetHashCode() GetType() ToString() Class EmpleadoBase Equals() GetHashCode() GetType() ToString() int IDEmpleado string NomEmpleado string ApellidosEmple string DNI EmpleadoBase : Empleado Class Empleado Equals() GetHashCode() GetType() ToString() int IDEmpleado string NomEmpleado string ApellidosEmple string DNI CalcularSalario() Miembros Heredados. float Salario

Ejemplo: Uso HerenciadeClases. Una subclase puede incorporar nuevos mtodos, propiedades y atributos. Dado que el constructor de la clase no es heredable, podemos hacer un constructor en la subclase que tome los valores del constructor de la clase superior. Esto se consigue utilizando la palabra clave: base. Ejemplo: Uso HerenciadeClasesConstructor.

3.4.1. Cambiar el funcionamiento de miembros en la subclase. Modificacin de los mtodos. 3.4.1.1. La palabra clave New. Una clase derivada o subclase nos permite modificar cualquier mtodo heredado de clase base. El objetivo de esta funcionalidad es redefinir el funcionamiento del mtodo en la subclase. El mtodo ha redefinir se llamar igual que en la clase base, con los mismo parmetros y devolver el mismo tipo de informacin. Tan slo se puede cambiar el contenido del mtodo, es decir, el espacio entre las dos llaves. Para ello, se usa la palabra new antes del tipo devuelto por el mtodo: public new void MetodoPrincipal(int numero)

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 33

El nuevo mtodo redefinido sustituye (oculta) al que tena la clase base, pero no lo elimina. Si instanciamos la subclase y en algn momento deseamos llamar al mtodo pero tal y como est en la clase base, utilizaremos la palabra reservada base. Ejemplo: Uso HerenciaClasesRedefinir Cuando usamos new como modificador del mtodo, oculta explcitamente un miembro heredado de una clase base. En este caso, la ocultacin reemplaza a la versin de la clase base. Aunque se puede ocultar mtodos de la clase base sin usar la palabra new, el compilador dar un mensaje de advertencia. Usando new, desaparece esta advertencia y registra la versin derivada como un reemplazo del mtodo de la clase base. El modificador New puede ser aplicado tambin atributos, propiedades, constantes, clases y estructuras. Ejemplo de uso aplicado a un mtodo:public class ClaseA { public int x; public void MetodoInvoke() { } } public class ClaseDerivadaA : ClaseA { new public void MetodoInvoke() { } }

Ejemplo de uso aplicado a una variable o atributo de la clase:public class ClaseB { public static int x = 55; public static int y = 22; } public class ClaseDerivadaB : ClaseB { // Oculta el campo X en la clase derivada. new public static int x = 100; public void Metodo() { // Muestra el nuevo valor de x: MessageBox.Show(X); // Muestra el valor oculto de x: MessageBox.Show(ClaseB.x); // Muestra el valor no oculto de y: MessageBox.Show(y); } }

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 34

Ejemplo aplicado a Clases:public class ClaseC { public class AnidadaC { public int x = 200; public int y; } } public class DerivadaC : ClaseC { // Oculta la clase AnidadaC de la ClaseC. new public class AnidadaC { public int x = 100; public int y; public int z; } static void Main() { // Creando Objetos desde la clase AnidadaC que oculta // a la clase AnidadaC de la clase Base: AnidadaC c1 = new AnidadaC(); // Creando Objetos desde la clase AnidadaC original: ClaseC.AnidadaC c2 = new ClaseC.AnidadaC(); MessageBox.Show (c1.x); MessageBox.Show (c2.x); } }

Este ltimo ejemplo est ocultando una clase anidada (AnidadaC), perteneciente a la clase de la que ha heredado: DerivadaC. Cuando usamos en el cdigo directamente AnidadaC, oculta la de la clase base y utiliza la clase que lleva el modificador new. Para usar la original, debemos de llamar primero a ClaseC y a continuacin a AnidadaC: ClaseC.AnidadaC c2 = new ClaseC.AnidadaC();

3.4.1.2. La palabra clave Override. El modificador Override es necesario para ampliar o modificar la implementacin abstracta o virtual de un mtodo, propiedad, indizador o evento heredado. Un mtodo override proporciona una nueva implementacin del miembro que se hereda de una clase base. El mtodo invalidado por una declaracin override se conoce como mtodo base invalidado. El mtodo que invalida al heredado, debe de tener la misma firma. Es decir, slo se puede cambiar el contenido o funcionalidad del mtodo, nunca la firma.Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 35

No se puede intentar invalidar un mtodo esttico o no virtual. Es decir, es necesario definir el mtodo en la clase base como virtual, abstract u override para poder aplicar el modificador override en la clase derivada. Si se trata de modificar un mtodo definido como override en la clase base, no podemos usar en la clase derivada los modificadores: new, static, virtual o abstract. Si nos referimos a propiedades de la clase, no podemos invalidar una propiedad en la clase derivada sin especificar el mismo modificador de acceso, tipo y nombre que la propiedad heredada. La propiedad invalidada debe ser virtual, abstract u override.

3.4.1.3. La palabra reservada Abstract El modificador abstract se puede utilizar con clases, mtodos, propiedades, indizadores y eventos. Se usa para indicar que la clase o miembro de la clase, debe de ser implementado por clases derivadas a la clase abstracta, o miembro abstracto. Las clases de tipo abstract presentan las siguientes caractersticas: No se pueden crear instancias de una clase abstracta. Una clase abstracta puede contener descriptores de acceso y mtodos abstractos. No se puede modificar una clase abstracta con el modificador sealed porque sealed impide que se herede la clase. Una clase no abstracta derivada de una clase abstracta debe incluir implementaciones reales de todos los descriptores de acceso y mtodos abstractos heredados. Utilice el modificador abstract en una declaracin de mtodo o propiedad para indicar que el mtodo o la propiedad no contienen implementacin. Los mtodos abstractos presentan las siguientes caractersticas: Un mtodo abstracto es, implcitamente, un mtodo virtual. Las declaraciones de mtodos abstractos slo se permiten en clases abstractas. Debido a que una declaracin de mtodo abstracto no proporciona una implementacin, no existe cuerpo del mtodo; la declaracin de mtodo finaliza simplemente con un punto y coma y sin llaves ({ }) despus de la firma. Por ejemplo: public abstract void MyMethod();Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 36

La implementacin la proporciona un mtodo de reemplazo override, que es miembro de una clase no abstracta. Utilizar los modificadores static o virtual en una declaracin de mtodo abstracto produce un error. Las propiedades abstractas funcionan como los mtodos abstractos, salvo las diferencias en la sintaxis de las declaraciones y llamadas. Es incorrecto utilizar el modificador abstract para una propiedad esttica. Una propiedad abstracta heredada se puede reemplazar en una clase derivada si se incluye una declaracin de propiedad que utilice el modificador override. Una clase abstracta debe proporcionar implementaciones para todos los miembros de la interfaz. Una clase abstracta que implementa una interfaz podra asignar los mtodos de la interfaz a mtodos abstractos. Por ejemplo:interface MiInterface { void Metodo(); } abstract class C : MiInterface { public abstract void Metodo(); }

Ejemplo de clases y miembros abstractos: Uso Abstract. En el ejemplo, la clase ClaseDerivada se deriva de una clase abstracta ClaseBase. La clase abstracta contiene un mtodo abstracto, AbstractMethod, y dos propiedades abstractas, X e Y. En la ClaseDerivada, por mediacin de override, se invalidan los miembros abstract por sus implementaciones. 3.4.1.4. La palabra reservada Sealed El modificador sealed, cuando se aplica a una clase, impide que otras clases hereden de esa clase. Por ejemplo:class ClaseA { internal int Numero; } sealed class ClaseB : ClaseA { internal string Texto; }

En este ejemplo, la ClaseB es sealed, lo que significa que no deja que se herede de ella. Pero eso no le impide que esta clase pueda heredar de otras clases, como por ejemplo, de la ClaseA.Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 37

El modificador sealed tambin puede utilizarse en un mtodo o propiedad que invalide un mtodo o propiedad virtual en una clase base. De esta forma, se puede permitir la derivacin de clases de la clase e impedir que se invaliden determinados mtodos o propiedades virtuales. Ver el siguiente ejemplo del uso de sealed:class ClaseX { protected virtual void F() { MessageBox.Show("X.F"); } protected virtual void F2() { MessageBox.Show("X.F2"); } } class ClaseY : ClaseX { sealed protected override void F() { MessageBox.Show("Y.F"); } protected override void F2() { MessageBox.Show("X.F3"); } } class ClaseZ : ClaseY { // Si se intenta invalidar el mtodo F en esta clase, tal y // como se puede ver: // protected override void F() { MessageBox.Show("C.F"); } // dara el error CS0239 durante la compilacin: // Por el contrario, al no ser un mtodo sealed, F2, si // permite su invalidacin. protected override void F2() { MessageBox.Show ("Z.F2"); } }

Conclusin a la herencia: 1. La subclase hereda todos los mtodos y propiedades de la clase base. 2. Asimismo la subclase puede incorporar nuevos mtodos y propiedades. Si la subclase crea un mtodo con idntico nombre al de la superclase, el mtodo de esta ltima se oculta y no puede ser accedido directamente. Para poder hacerlo se usar la palabra reservada base, seguido del nombre del mtodo: base.NombreMetodoPrincipal 3. Los objetos Private de la Superclase no son accesibles por la subclase. 4. Los objetos Protected, Intenal y Public s son accesibles por la subclase. 5. Los mtodos Protected se comportan como si fueran Private para otros mtodos de otras clases, pero no para los mtodos de la subclase, conCaptulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 38

independencia del espacio de nombres al que pertenezcan, para lo cual son a todos los efectos Public. 6. Los miembros heredados por una subclase, pueden a su vez, ser heredados por otras subclase, lo que se conoce como propagacin de la herencia.

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 39

3.5. PolimorfismoSe conoce como polimorfismo la posibilidad de asumir muchas formas. En nuestro caso, es la posibilidad de que un mtodo definido en una superclase pueda ser redefinido en sus clases derivas, pero usando siempre el acceso por referencia a la Superclase. En C#, el polimorfismo se consigue definiendo los mtodos de la superclase que se deben comportar as como virtual y los mtodos del mismo nombre en las clases derivadas, como override. En .Net, cada tipo es polimrfico porque todos los tipos, incluidos los tipos definidos por el usuario, heredan de Object. A menudo se hace referencia al polimorfismo como el tercer pilar de la programacin orientada a objetos, tras la encapsulacin y la herencia. El trmino polimorfismo es una palabra griega que significa "con muchas formas" y tiene dos aspectos que lo caracterizan: En tiempo de ejecucin, los objetos de una clase derivada se pueden tratar como objetos de una clase base en lugares como parmetros de mtodo y colecciones o matrices. Cuando esto sucede, el tipo declarado del objeto ya no es idntico a su tipo en tiempo de ejecucin. Las clases base pueden definir e implementar mtodos virtuales y las clases derivadas pueden invalidarlos (override), lo que significa que proporcionan su propia definicin e implementacin. En tiempo de ejecucin, cuando el cdigo de cliente llama al mtodo, CLR busca el tipo en tiempo de ejecucin del objeto e invoca esta invalidacin del mtodo virtual. As, en el cdigo fuente puede llamar a un mtodo de una clase base y provocar la ejecucin de la versin de clase derivada del mtodo. Los mtodos virtuales permiten trabajar con grupos de objetos relacionados de una manera uniforme. Por ejemplo, supongamos que disponemos de una aplicacin de dibujo que permite a un usuario crear varios tipos de formas en una superficie de dibujo. En tiempo de compilacin no se conocen los tipos especficos de formas que crear el usuario. Sin embargo, la aplicacin tiene que realizar el seguimiento de los diferentes tipos de formas que se crean y tiene que actualizarlos como respuesta a las acciones del usuario. Se puede utilizar el polimorfismo para resolver este problema en dos pasos bsicos: Se creea una jerarqua de clases en la que cada clase de forma especfica derive de una clase base comn. Se utiliza un mtodo virtual para invocar el mtodo adecuado de una clase derivada a travs de una nica llamada al mtodo de clase base.Captulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 40

Ver Ejemplo: Uso Polimorfismo. Explicacin del ejemplo: En primer lugar, se crea una clase base llamada Shape y clases derivadas como Rectangle, Circle y Triangle. Se incluye en la clase Shape un mtodo virtual llamado Draw y se invalida en cada clase derivada para dibujar la forma determinada que representa la clase. Se crea un objeto List y se agrega elementos Circle, Triangle y Rectangle a l. Para actualizar la superficie de dibujo, se utiliza un bucle foreach para recorrer en iteracin la lista y llamar al mtodo Draw en cada objeto Shape de la lista. Aunque cada objeto de la lista tiene un tipo declarado de Shape, es el tipo en tiempo de ejecucin (la versin invalidada del mtodo en cada clase derivada) al que se invocar.

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 41

3.6. InterfacesLas interfaces, al igual que las clases, definen un conjunto de miembros, pero a diferencia de estas, no proporcionan la implementacin para los miembros. Una interface slo puede contener como miembros: mtodos, propiedades, eventos e indizadores. Una interfaz tiene un modificador de acceso, al igual que las clases y con los mismas aplicaciones; a continuacin la palabra clave interface; y despus el nombre de la interfaz. Ejemplo:public interface IFecha { int Dia(); int Mes(); int Year(); } class CuentaAhorro : Cuenta, IFecha { public int Dia() { return DateTime.Now.Day; } public int Mes() { return DateTime.Now.Month; } public int Year() { return DateTime.Now.Year; } }

En este ejemplo que acabamos de ver, hemos definido una clase llamada, CuentaAhorro, que hereda de una clase base llamada Cuenta. Adems, hereda de una interfaz llamada IFecha, pero IFecha slo contiene la firma de los mtodos que debemos implementar en la clase. Por eso, dentro de la clase CuentaAhorro, hacemos la implementacin del cdigo de los mtodos que fueron definidos en la interfaz IFecha. Una interfaz puede heredar de ms de una interfaz y puede ser definida dentro de un espacio de nombres o dentro de una clase. Aunque en C# slo admite la herencia bsica, es decir, slo puede heredar de una clase, en cuanto a la herencia de interfaz, permite tantas como se quiera. La siguiente declaracin de una class estara permitida: class CuentaAhorro : Cuenta, IFecha, IDatosCaptulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 42

Una clase que implementa una interfaz puede implementar explcitamente miembros de esa interfaz. A un miembro implementado explcitamente slo se puede tener acceso mediante una instancia de la interfaz, y no mediante una instancia de la clase. Todos los miembros de una interfaz tienen nivel de acceso public de forma automtica. Por ejemplo: si una clase implementa dos interfaces que contienen un miembro con la misma firma, la implementacin de ese miembro en la clase har que ambas interfaces usen ese miembro como implementacin. Por ejemplo:interface IControl { void Paint(); } interface ISurface { void Paint(); } class EjemploInterfaz : IControl, ISurface { //Ambas:ISurface.Paint y IControl.Paint llaman a este mtodo. public void Paint() { } }

Si el mtodo Paint de las dos interfaz tuviera una firma diferente en cada una de ellas, esta implementacin que acabamos de ver dara un error. Para solucionarlo, es necesario implementar la interfaz y su mtodo de forma explcita. Para ello, usamos una instancia de la interfaz, en lugar de una instancia de la clase, tal y como podemos ver en el siguiente ejemplo:interface IControl { void Paint(); } interface ISurface { string Paint(); } public class EjemploInterfazExpli : IControl, ISurface { void IControl.Paint() { MessageBox.Show("IControl.Paint"); } string ISurface.Paint() { MessageBox.Show ("ISurface.Paint"); return " "; } }

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 43

public partial class Principal : Form { private void Metodo(object sender, EventArgs e) { EjemploInterfazExpli objEjemplo = new EjemploInterfazExpli(); //Instanciamos la Interfaz en lugar de la Class IControl objIControl = (IControl)objEjemplo; objIControl.Paint(); //Muestra en pantalla "IControl.Paint" ISurface objISurface = (ISurface)objEjemplo; objISurface.Paint(); //Muestra en pantalla "ISurface.Paint" } }

Para implementar un miembro de interfaz, el miembro correspondiente de la clase debe ser pblico, no esttico y tener el mismo nombre y la misma firma que el miembro de interfaz. Las propiedades e indizadores de una clase pueden definir descriptores de acceso adicionales para una propiedad o indizador definidos en una interfaz. Por ejemplo, una interfaz puede declarar una propiedad con un descriptor de acceso get, pero la clase que implementa la interfaz puede declarar la misma propiedad con descriptores de acceso get y set. Sin embargo, si la propiedad o el indizador utiliza una implementacin explcita, los descriptores de acceso deben coincidir. Las interfaces pueden heredar otras interfaces. Es posible que una clase herede una interfaz varias veces, a travs de las clases base o interfaces que hereda. En ese caso, la clase slo puede implementar la interfaz una vez, siempre que sta se declare como parte de la nueva clase. Si la interfaz heredada no est declarada como parte de la nueva clase, la clase base que la declar proporcionar su implementacin. Es posible que una clase base implemente miembros de interfaz a travs de miembros virtuales. En ese caso, la clase que hereda la interfaz puede cambiar el comportamiento de la interfaz reemplazando los miembros virtuales. Una interfaz tiene las siguientes propiedades: Una interfaz es como una clase base abstracta: cualquier tipo no abstracto que hereda la interfaz debe implementar todos sus miembros. No se pueden crear instancias directamente de una interfaz. Las interfaces pueden contener eventos, mtodos, indizadores y propiedades. Las interfaces no contienen implementaciones de mtodos. Las clases y estructuras se pueden heredar de ms de una interfaz. Una interfaz se puede heredar de varias interfaces.

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 44

Objetivo de la Interface: 1. Declarar mtodos que una o ms clases deben de implementar en determinadas situaciones. 2. Publicar la interface de programacin de una clase sin descubrir cmo estn implementados los mtodos. 3. Permitira agrupar las clases en matriz objetos y aplicar polimorfismo.

Las clases Static y su miembrosUna clase esttica es bsicamente igual que una clase no esttica, pero existe una diferencia: no se pueden crear instancias de una clase esttica. En otras palabras, no se puede utilizar la palabra clave new para crear una variable del tipo clase. Dado que no hay ninguna variable de instancia, el acceso a los miembros de una clase esttica se realiza mediante el propio nombre de clase. Por ejemplo, si tenemos una clase esttica que llamada Persona e incluye un mtodo pblico denominado BuscarPersona, la llamada al mtodo se realiza tal y como se muestra en el ejemplo siguiente: Persona.BuscarPersona(); Como sucede con todos los tipos de clase, Common Language Runtime (CLR) de .NET Framework carga la informacin de tipo de una clase esttica cuando se carga el programa que hace referencia a la clase. El programa no puede especificar exactamente cuando se carga la clase. Sin embargo, se garantiza que se ha cargado, que sus campos se han inicializado y que se ha llamado a su constructor esttico antes de que se haga referencia a la clase por primera vez en el programa. Solo se llama una vez a un constructor esttico y una clase esttica permanece en memoria durante el perodo de duracin del dominio de aplicacin donde reside el programa. Las clases estticas son de tipo sealed y, por consiguiente, no pueden heredarse. No pueden heredar de cualquier clase, excepto Object. Las clases estticas no pueden contener un constructor de instancia; sin embargo, pueden contener un constructor esttico. Las clases no estticas tambin deben definir un constructor esttico si contienen miembros estticos que requieren una inicializacin.

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 45

3.7. Documentacin de Cdigo. Uso de etiquetas XML.Las aplicaciones actuales de XML son casi infinitas, desde el ao 2000 que empez a tomarse como un estndar apropiado para el intercambio de datos entre plataformas, el uso y aplicacin del mismo ha ido creciendo de una forma exponencial. En Net Framework disponemos de la posibilidad de documentar nuestro cdigo utilizando etiquetas XML dentro del cdigo, para de esta forma, tener la ayuda y la documentacin tcnica sin necesidad de crearla por separado como ocurra antiguamente. A continuacin vemos las etiquetas ms utilizadas en .Net:

. La etiqueta se utiliza para describir un tipo o unmiembro de tipo. Utilice para suministrar informacin adicional a una descripcin de tipo. El texto de la etiqueta es la nica fuente de informacin sobre el tipo en IntelliSense y tambin se muestra en el Examinador de objetos. Ejemplo:/// /// Informacin sobre la clase ///

. La etiqueta se utiliza para agregar informacin sobreun tipo, de modo que completa la informacin especificada con . Esta informacin se muestra en el Explorador de objetos./// /// Informacin sobre la clase /// /// /// Contenido Adicional sobre la clase. /// class Program {}

y . La etiqueta proporciona un modo de indicar que el textode una descripcin se debe marcar como cdigo. Utilice para marcar varias lneas como cdigo. Ejemplo:/// /// Se resetea el valor para ContadorID ///

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 46

/// /// /// ///

Producto obj = new Producto(); obj.IdProducto = 4

. La etiqueta permite especificar un ejemplo de cmoutilizar un mtodo u otro miembro de una biblioteca. Generalmente, esto supone utilizar la etiqueta Ejemplo:public class Empleado { /// /// Ejemplo de uso del campo IDEmpleado /// /// Empleado obj = new Empleado(); /// obj.IDEmpleado = 21 /// /// /// public int IDEmpleado; }

. Especifica las excepciones que se pueden producir.Sintaxis:Descripcin

Parmetros: cref. Referencia a una excepcin disponible desde el entorno de compilacin actual. El compilador comprueba si existe la excepcin dada y convierte member al nombre de elemento cannico en el resultado XML. member debe aparecer entre comillas dobles (" "). Descripcin. Descripcin de la excepcin. Se utiliza la etiqueta para especificar las excepciones que se pueden producir. Esta etiqueta se aplica a una definicin de mtodo. Ejemplo:/// Lanzar cuando Matriz es null static void Main(string[] args) { string[] Matriz; }

. La etiqueta permite hacer referencia a comentarioscolocados en otro archivo que describen los tipos y miembros del cdigo fuente. sta es una alternativa al mtodo habitual de colocar los comentariosCaptulo 3. Diseo de Aplicaciones Orientadas a Objetos Pgina 47

de la documentacin directamente en el archivo de cdigo fuente. La etiqueta utiliza la sintaxis XPath de XML. Sintaxis:

Parmetros: Fichero. Nombre del archivo que contiene la documentacin. El nombre de archivo se puede completar con una ruta de acceso. Agregue filename entre comillas simples (' '). Tagpath. Ruta de acceso de las etiquetas de filename que conduce a la etiqueta name. La ruta de acceso va entre comillas simples (' '). Nombre. Especificador de nombre en la etiqueta que precede a los comentarios; Nombre poseer un id. Id. Identificador para la etiqueta que precede a los comentarios. El id va entre comillas dobles (" ").

Ejemplo:/// class Test {}

. El bloque se utiliza para definir la fila de encabezado deuna tabla o de una lista de definiciones. Cuando se define una tabla, slo es necesario suministrar una entrada para un trmino en el encabezado. Cada elemento de la lista se especifica con un bloque . Cuando se crea una lista de definiciones, se debern especificar tanto term como description. Sin embargo, para una tabla, lista con vietas o lista numerada, slo es necesario suministrar una entrada para description. Una lista o una tabla pueden tener tantos bloques como sean necesarios. Sintaxis: Termino Descripcin... term Descripcin...

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 48

Parmetros Term. Trmino que se define en description. Description. Elemento de una lista numerada o con vietas, o definicin de un term. Ejemplo:/// Ejemplo de tipo Dato: /// /// /// Item 1. /// /// /// Item 2. /// /// /// static void Main() { }

. La etiqueta se utiliza dentro de otra etiqueta, tal como, o , y permite dar una estructura al texto. Ejemplo:/// Mtodo Principal de la Aplicacin /// Aqu se puede hacer un segundo prrafo en la descripcion /// /// para informacin acerca de los parmetros de salida. /// ///

. La etiqueta se debe utilizar en el comentario de unadeclaracin de mtodo para describir uno de los parmetros del mtodo. El texto para la etiqueta se mostrar en IntelliSense, el Examinador de objetos y en el Informe Web de comentario de cdigo. Sintaxis:description

Parmetros Name. Nombre de un parmetro de mtodo. Colocar el nombre entre comillas dobles (" "). Description. Descripcin del parmetro.

Captulo 3. Diseo de Aplicaciones Orientadas a Objetos

Pgina 49