Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Interfaces
Interfaces
Las interfaces son un elemento bastante importante en .NET Framework, ya que de hecho se utiliza con bastante frecuencia, en esta leccin veremos que son las interfaces y como utilizarlas en nuestros proyectos, tambin veremos que papel juegan en .NET y cmo aplicar algunas de las definidas en la biblioteca base.
Qu es una interfaz?
Las interfaces son una forma especial de una clase, aunque la diferencia principal con las clases es que las interfaces no contienen cdigo ejecutable, solo definen los miembros y, en el caso de los mtodos, si reciben parmetros y de que tipo son. Las interfaces se utilizan para indicar el "comportamiento" que tendr una clase, o al menos qu miembros debe definir esa clase. Para definir una interfaz en C# tenemos que usar la instruccin interface seguida del nombre y encerrado entre un par de llaves los miembros que define:
public interface IAnimal { //... }
Tal como comentamos en el apartado de la accesibilidad, los miembros de una interfaz siempre son pblicos, pero no debemos indicarlo, ya que se sobreentiende que es as y el compilador producira un error indicndonos que el modificador de accesibilidad no se puede aplicar a ese tipo de elementos. Como los miembros de las interfaces no contienen cdigo ejecutable, solo debemos definir la "firma" del mtodo, propiedad o evento que queremos definir. En el caso de las propiedades, tendremos que indicar los bloques get y/o set que la clase o tipo que la implemente debe definir.
public interface IAnimal { void Desplazar(); void Alimentarse(); string Especie { get; set;} int Edad { get;} }
Nota: Segn las indicaciones de nomenclatura de .NET Framework, se recomienda que todas las interfaces empiecen con una I mayscula seguida del nombre al que hacer referencia la interfaz.
Si estamos usando el IDE de Visual C# 2005, al escribir el nombre de la interfaz, tal como podemos ver en la figura 2.9, nos indicar s queremos implementar los miembros de esa interfaz.
Figura 2.9. Ayuda del IDE de Visual C# 2005 para implementar una interfaz en una clase
Las opciones ofrecidas por el IDE de C# son dos, aunque la primera ser la que utilicemos con ms frecuencia. En la figura 2.10 podemos ver las dos opciones que nos ofrece:
Figura 2.10. Las dos opciones de implementacin ofrecidas por el IDE de Visual C# 2005
public void Mostrar() { throw new Exception("The method or operation is not implemented."); }
public string Saludo(string nombre) { throw new Exception("The method or operation is not implemented."); }
public string Nombre { get { throw new Exception("The method or operation is not implemented."); } set { throw new Exception("The method or operation is not implemented."); } }
public int Edad { get { throw new Exception("The method or operation is not implemented."); } }
public string this[int index] { get { throw new Exception("The method or operation is not implemented."); } set
public IPrueba this[string index] { get { throw new Exception("The method or operation is not implemented."); } }
#endregion }
Como podemos apreciar, no solo ha aadido las definiciones de cada miembro de la interfaz, sino que tambin aade cdigo extra a cada uno de esos miembros con idea de que nos demos cuenta de que debemos escribir el nuestro propio. Tambin podemos apreciar que lo nico que ha hecho el IDE de C# es declarar cada uno de los miembros de la interfaz, pero no ha relacionado esos miembros con los definidos en la interfaz, para C# no es necesario hacer esa liga, ya que lo nico que le basta para crear esa relacin es que el miembro de la clase se llame igual que el de la interfaz y que tenga el mismo nmero de parmetros, tipos, etc., es decir, que tenga la misma "firma". Adems, comprobamos que todos los miembros los ha definido como pblicos, esto realmente no es obligatorio, y podemos cambiarlos a privado, interno o como queramos, pero debemos saber que en cualquier caso, aunque un mtodo lo hayamos declarado como privado en la clase, siempre ser accesible por medio de un objeto del tipo de la interfaz, pero de esto nos ocuparemos en la siguiente seccin.
p.Mostrar();
O bien de forma indirecta, por medio de una variable del mismo tipo que la interfaz:
Prueba prueba1 = new Prueba(); IPrueba interfaz1;
interfaz1 = prueba1;
interfaz1.Mostrar();
Qu ocurre aqu? Como ya comentamos anteriormente, cuando asignamos variables por referencia, realmente lo que asignamos son referencias a los objetos creados en la memoria, por tanto la variable interfaz1 est haciendo referencia al mismo objeto que prueba1, aunque esa variable solo tendr acceso a los miembros de la clase Prueba que conoce, es decir, los miembros definidos en IPrueba. Si la clase define otros miembros que no estn definidos en la interfaz, la variable interfaz1 no podr acceder a ellos.
De esta forma nos aseguramos de que el cdigo se ejecutar solamente si la variable prueba1 contiene una definicin de la interfaz IPrueba. Si lo que queremos hacer es trabajar con objetos que implementen una interfaz en concreto, por ejemplo, podemos tener el siguiente cdigo en el que si el objeto comprobado implementa la interfaz IPrueba llamaremos al mtodo Mostrar:
static void comprobarIPrueba(object o) { if (o is IPrueba) ((IPrueba)o).Mostrar(); }
En este ejemplo, el parmetro es de tipo object, que es el que sirve como base de todas las clases de .NET, hacemos la comprobacin de que implementa la interfaz IPrueba, si es as, haciendo una conversin (cast) llamamos al mtodo Mostrar, hay que notar los parntesis que encierran el cast de la variable o para poder acceder al mtodo, ya que si no lo hacemos el compilador entender que queremos convertir o.Mostrar() al tipo IPrueba, aunque antes de llegar ah, nos dar un error de compilacin indicndonos que object no implementa Mostrar. Pero si en lugar de hacer una simple llamada a un mtodo del objeto necesitamos hacer ms cosas, el cdigo que usaramos sera algo as:
static void comprobarIPrueba(object o) { if (o is IPrueba) { IPrueba unaPrueba = (IPrueba)o; unaPrueba.Mostrar(); Console.WriteLine(unaPrueba.Saludo(unaPrueba.Nombre)); } }
Es decir, que no solo llamamos a un mtodo, sino que hacemos una conversin que asignamos a un objeto y despus usamos ese objeto para llamar a los mtodos y propiedades que queramos. En este ejemplo solo usamos dos de los miembros de ese objeto, pero podramos usar ms. En estos casos, es preferible usar otra instruccin de C#: as. Con as hacemos una conversin al tipo indicado y si no es de ese tipo devuelve un valor nulo, y si lo es, devuelve una referencia al objeto de ese tipo:
static void comprobarIPrueba2(object o) {
En este caso, asignamos a la variable unaPrueba el contenido de la variable o, pero tomando la implementacin de IPrueba, (si es que la tiene), en caso de que el valor devuelto no sea nulo, usamos ese objeto. Aunque pueda parecer que es lo mismo usar is o as, al menos por el nmero de lneas de cdigo, debemos saber que el cdigo generado por el compilador al usar la instruccin as es ms compacto que el de la instruccin is.
Ni que decir tiene que debemos implementar todos los miembros de todas las interfaces indicadas.
Por ejemplo, si tenemos las siguientes interfaces y las implementamos en la clase Prueba3, el cdigo quedara de la siguiente forma:
public interface IPrueba2 { void Mostrar(); string Nombre { get; set;} }
public class Prueba3 : IPrueba2, IMostrar { public void Mostrar() { Console.WriteLine("Mostrar en Prueba3"); } private string nombre; public string Nombre { get{ return nombre; } set{ nombre = value; } } }
Implementacin privada
Tal como hemos visto en la seccin anterior, podemos implementar ms de una interfaz en una misma clase, adems si existen mtodos con la misma "firma" en las interfaces, C# utiliza solo un mtodo para todos los mtodos que tengan esa
firma. Aunque es posible que queramos que no todos los miembros que tengan la misma firma utilicen el mismo mtodo pblico de la clase, o bien puede que queramos implementar una interfaz sin que se expongan los miembros como parte pblica de la clase, en esos casos, tambin podremos acceder a esos miembros privados, aunque siempre por medio de un objeto del mismo tipo que la interfaz. En estos casos, podemos usar lo que el IDE de C# llama "implementacin explcita de una interfaz", (ver figura 2.10). Si nos decidimos por esa opcin, el cdigo generado por el IDE para la clase Prueba3 del ejemplo de la seccin anterior, quedara de esta forma:
public class Prueba3 : IPrueba2, IMostrar { public void Mostrar() { Console.WriteLine("Mostrar en Prueba3"); } private string nombre; public string Nombre { get{ return nombre; } set{ nombre = value; } }
IMostrar.Mostrar() no formara parte de la clase Prueba3, salvo que usemos un objeto del tipo IMostrar, tal como vemos en la figura 2.11:
Resumiendo: podemos implementar varias interfaces y tambin podemos decidir si queremos que esas implementaciones sean visibles a travs de la propia clase o por medio de objetos del tipo de la interfaz implementada.
derive" de otra clase que implementa alguna interfaz, la nueva clase tambin incorporar esa interfaz.
Si en una clase implementamos una interfaz que a su vez implementa otras interfaces, esa clase tendr definiciones de todos los miembros de todas las interfaces, por ejemplo, si tenemos la siguiente definicin de la interfaz IPrueba3 que "implementa" la interfaz IMostrar:
public interface IPrueba3 : IMostrar { string Saludo(string nombre); string Nombre{get; set;} }
Y la clase Prueba4 implementa IPrueba3, la definicin de los miembros quedara de la siguiente forma:
public class Prueba4 : IPrueba3 { #region IPrueba3 Members public string Saludo(string nombre) { // El mtodo Saludo de IPrueba3 } // La propiedad Nombre de IPrueba3 public string Nombre { get{ ... } set{ ... } } #endregion
En este cdigo, el mtodo Mostrar se indica mediante la interfaz IMostrar, pero tambin se puede hacer por medio de IPrueba3.Mostrar, ya que IPrueba3 tambin lo implementa (o hereda).
En el mtodo CompareTo hacemos una comprobacin de que el objeto con el que debemos realizar la comparacin es del tipo Empleado, en ese caso convertimos el objeto pasado en uno del tipo Empleado y comparamos los nombres. Si el objeto que recibe el mtodo no es del tipo Empleado, devolvemos un cero, para indicar que no haga ninguna clasificacin, ya que ese valor indica que los dos objetos son iguales. Esta clase la podemos usar de esta forma:
// Una coleccin de datos del tipo Empleado List<Empleado> empleados = new List<Empleado>();
// Aadimos varios empleados a la coleccin empleados.Add(new Empleado("Pepe")); empleados.Add(new Empleado("Bernardo")); empleados.Add(new Empleado("Juan")); empleados.Add(new Empleado("Ana"));
// La clasificamos empleados.Sort();
Console.WriteLine(e1.Nombre);
Al llamar al mtodo Sort de la coleccin empleados, se utilizar la implementacin del mtodo CompareTo que es el encargado de indicar en que orden deben ir los datos. Si nuestra clase Empleado tuviese que hacer la clasificacin basndose en otras propiedades, sera en el mtodo CompareTo donde habra que hacer la decisin de que valor devolver, teniendo en cuenta de que un valor cero indica que los dos objetos son iguales, un valor menor que cero que nuestro objeto debe ir antes que el indicado en el parmetro y un valor mayor de cero para indicar que nuestro objeto debe ir despus del indicado. El resultado de este cdigo sera el siguiente: Ana Bernardo Juan Pepe