JASoft.org

El blog de José Manuel Alarcón Aguín. Programación web y mucho más...

MENÚ - JASoft: JM Alarcón

Implementación de interfaces: implícitas vs explícitas - O cómo ocultar miembros de interfaces

Las interfaces en .NET y otros lenguajes son una manera de establecer un contrato entre dos clases, de manera que dejemos perfectamente definido de qué manera vana poder interactuar entre ellas. Así, si una clase implementa una determinada interfaz sabemos que dicha clase va a disponer de determinados métodos y podemos contar con ellos a la hora de trabajar con ésta. Además gracias a las interfaces podemos implementar ciertos tipos de polimorfismo o genericidad a la hora de trabajar con conjuntos de clases que implementan la misma interfaz.

En fin, nada nuevo en el párrafo anterior para un programador mínimamente experimentado de .NET o cualquier otro lenguaje orientado a objetos. En nuestro curso de preparación del examen 70-536 se trata profusamente este tema, como es lógico. Lo interesante, y objeto de este post, viene a la hora de decidir cómo implementar una determinada interfaz en una clase. Así, si tenemos definida una interfaz cualquiera, por ejemplo esta:

public interface IMiInterfaz
{
	void MiMetodo();
}

Tenemos dos formas de implementarla en una clase. La primera de ellas es la manera implícita:

public class PruebaInterfazImplicita : IMiInterfaz
{
	public void MiMetodo()
	{
		Console.WriteLine("Hola");
	}
}

La otra manera es la explícita, en la que indicamos de manera evidente qué interfaz estamos implementando:

public class PruebaInterfazExplicita : IMiInterfaz
{
	void IMiInterfaz.MiMetodo()
	{
		Console.WriteLine("Hola");
	}
}

Fíjate que en este caso ponemos el nombre de la interfaz delante del método para indicar a qué interfaz pertenece éste, y además el método no es público.

Generalmente los programadores no le damos importancia a la forma en la que se implementa una interfaz y se usan indistintamente ambas formas, pero ¿realmente existe alguna diferencia?

Pues sí, hay diferencias y son importantes. A continuación resumiré los detalles relacionados con la implementación de interfaces y con qué cosas debemos tener cuidado.

1.- Implementación de varias interfaces

En .NET no existe la herencia múltiple de clases. Algunos alegarán que es una carencia, y otros dirán que es incluso una ventaja. Se ha escrito mucho sobre el tema. Lo que sí está permitido es la implementación de diversas interfaces. Así, si tenemos dos interfaces que definen métodos con el mismo nombre ¿cómo distinguimos unos de otros?. Por ejemplo, si tenemos dos interfaces I1 e I2 así:

public interface I1
{
	void M();
}

public interface I2
{
	void M();
}

public class PruebaDobleInterfaz : I1, I2
{
	public void M()
	{
		Console.WriteLine("Método M");
	}
}


public class Prueba
{
	public static void Main()
	{
		PruebaDobleInterfaz obj = new PruebaDobleInterfaz();
		obj.M();
		((I1) obj).M();
		((I2) obj).M();
		Console.Write("Pulsa una tecla para terminar...");
		Console.ReadKey();
	}
}

¿Cual será el resultado del código anterior? Pues que funcionará perfectamente y obtendremos el mismo texto tres veces, resultado de llamar al método M. Esto está genial si realmente queremos que la implementación del método sea idéntica en ambos casos, pero al tratarse de interfaces diferentes generalmente no será así. Ahí es donde entra la implementación explícita, ya que indicaremos qué interfaz exactamente estamos implementando y no habrá confusión posible. Si ahora definimos la clase así:

public class PruebaDobleInterfaz : I1, I2
{
	public void M()
	{
		Console.WriteLine("Método M");
	}
	
	void I1.M()
	{
		Console.WriteLine("Método I1.M");
	}
	
	void I2.M()
	{
		Console.WriteLine("Método I2.M");
	}
}

Pues ahora el código anterior mostrará tres mensajes diferentes, dependiendo de si llamamos al método M en la clase, o en una interfaz específica.

2.- Ocultar la implementación de miembros de interfaces

Al implementar de manera explícita miembros de interfaces lo que conseguimos es ocultarlos frente a su uso directo en la clase. Por ejemplo:

public interface IMiInterfaz
{
	void MiMetodo();
}

public class PruebaInterfazImplicita : IMiInterfaz
{
	void IMiInterfaz.MiMetodo()
	{
		Console.WriteLine("Hola");
	}
}

public class Prueba
{
	public static void Main()
	{
		PruebaInterfazImplicita obj = new PruebaInterfazImplicita();
		//obj.MiMetodo(); //Produce un error de compilación de que la clase no contiene ese método
		((IMiInterfaz) obj).MiMetodo();
		Console.Write("Pulsa una tecla para terminar...");
		Console.ReadKey();
	}
}

Fíjate que ahora la llamada al método implementado explícitamente falla cuando lo intentamos hace directamente desde la clase, y se requiere el "casting" explícito a la interfaz para poder llamarlo. Además el método nose mostrará a los programadores en el Intellisense de Visual Studio, por lo que n tendrán la tentación de usarlo de cualquier manera, ocultándolo efectivamente.

¿Para qué podría servir esto? Pues por ejemplo para ocultar ciertos miembros que queremos que se usen con cuidado y sabiendo lo que se hace. Por ejemplo, es muy típico hacer esto al utilizar la interfaz IDisposable, ocultando la implementación del método Dispose() que debe ser llamado por el runtime y no generalmente por el programador.

3.- Ni públicos, ni virtuales ni abstractos

Los métodos de interfaces implementados de manera explícita no pueden definirse como públicos (se declaran automáticamente como privados para ocultarlos) ni tampoco como abstractos o virtuales. Hay que tenerlo en cuenta por si lo necesitásemos. Esto tiene dos importantes implicaciones:

1.- las clases que implementan interfaces de manera explicita no pueden ser abstractas.
2.- Las clases derivadas de clases que implementan interfaces de manera explícita no pueden sobrescribir los métodos definidos explícitamente.

Detalles adicionales

Si quieres ver algunos ejemplso más de cómo implementar interfaces explícitamente puedes echarle un vistazo a este documento de MSDN (en español): Tutorial de implementación explícita de interfaces.

Si ya dominas el tema y quieres profundizar para conocer los detalles de bajo nivel de cómo se implementan por debajo ambas formas de declarar métodos de interfaces, te recomiento este excelente artículo sobre el asunto de Chris Brumme, ingeniero distinguido de Microsoft, aquí: "cbrumme's Weblog: Interface Layout". ¡Realmente interesante!

Espero que te haya resultado interesante, aunque sea algo árido :-)

José Manuel Alarcón
Banner

Comentarios (1) -

Excelente foro con informacion que me sera de mucha ayuda, muchas gracias y saludos a todos los foristas.

Responder

Agregar comentario