[C# Básico] Interfaces

Hola a todos! El otro día recibí un correo que decía lo siguiente:

¿Podrías escribir algo sobre el uso de Interfaces? Yo por ahi he leido que es algo recomendado crear interfaces que es como un patrón.. Yo la verdad no las uso en mis proyectos pero me gustaría saber para qué sirven y porque se deberían usar y en qué casos.

Reconozco que es un correo para reflexionar: muchas veces tendemos a escribir sobre lo más: lo más avanzado, lo más novedoso, lo más cool… y quizá nos olvidamos de que hay gente que lo que busca son artículos para iniciarse. Es cierto que Tutoriales de C# los hay a patadas en internet, pero una cosa es un tutorial planteado como un curso y otra un pequeño post sobre algún tema básico concreto.

Por esto me he decidido a hacer este post. Como digo en el título es C# básico, pero si como quien me mandó el correo, tienes dudas sobre como funcionan las interfaces en C#… bienvenido a bordo! 😉

Seguiré la serie [C# Básico] si veo que hay demanda de ella, es decir que si alguien me propone que escriba sobre temas concretos (a nivel de introducción) no tengo ningún problema en hacerlo! 🙂

1.¿ Que es la interfaz de una clase?

En teoría de orientación a objetos, la interfaz de una clase es todo lo que podemos hacer con ella. A efectos prácticos: todos los métodos, propiedades y variables públicas (aunque no deberían haber nunca variables públicas, debemos usar propiedades en su lugar) de la clase conforman su interfaz.

Dada la siguiente clase:

class Contenedor
{
public int Quitar();
public void Meter(int v);
private bool EstaRepetido(int v);
}

Su interfaz está formada por los métodos Quitar y Meter. El método EstaRepetido no forma parte de la interfaz de dicha clase, ya que es privado.

En orientación a objetos decimos que la interfaz de una clase define el comportamiento de dicha clase, ya que define que podemos y que no podemos hacer con objetos de dicha clase: dado un objeto de la clase Contenedor yo puedo llamar al método Quitar y al métdo Meter pero no puedo llamar al método EstaRepetido.

Así pues: toda clase tiene una interfaz que define que podemos hacer con los objetos de dicha clase.

2. Interfaces idénticas no significa clases intercambiables

Fíjate en estas dos clases:

class Contenedor
{
public int Quitar() { ... }
public void Meter (int v) { ... }
}
class OtroContenedor
{
public int Quitar() { ... }
public void Meter (int v) { ... }
}

Que puedes deducir de ellas? Exacto! Su inerfaz es la misma: con ambas clases podemos hacer lo mismo: llamar al método Quitar y al método Meter.

Ahora imagina que en cualquier otro sitio tienes un método definido tal y como sigue:

public void foo (Contenedor c)
{
// Hacer cosas con c como p.ej:
int i = c.Quitar();
c.Meter(10);
}

El método recibe un Contenedor y opera con él. Ahora dado que las interfaces de Contenedor y OtroContenedor son iguales, uno podría esperar que lo siguiente funcionase:

OtroContenedor oc = new OtroContenedor();
foo(oc);

Pero esto no va a compilar. ¿Por que? Pues aunque nosotros somos capaces leyendo el código de comparar la interfaz de ambas clases, el compilador no puede hacer esto. Para el compilador Contenedor y OtroContenedor son dos clases totalmente distintas sin ninguna relación. Por lo tanto un método que espera un Contenedor no puede aceptar un objeto de la clase OtroContenedor.

Quiero recalcar que el hecho de que el compilador no compare las interfaces de las clases no se debe a una imposibilidad técnica ni nada parecido: se debe a que no tiene sentido hacerlo.

¿Por que? Pues simplemente porque las interfaces son idénticas por pura casualidad. Supón que fuese legal llamar a foo con un objeto OtroContenedor, ok?

Entonces podría pasar lo siguiente:

  1. Alguien añade un método público a la clase Contenedor.
  2. Se modifica el método foo para que llame a dicho método nuevo. Eso es legal porque foo espera un Contenedor como parámetro
  3. La llamada a foo(oc) donde oc es OtroContenedor… como debe comportarse ahora? OtroContenedor no tiene el método nuevo que se añadió a Contenedor!

Así pues: dos clases con la misma interfaz no tienen relación alguna entre ellas y por lo tanto no se pueden intercambiar.

3. Implementación de interfaces

El ejemplo anterior ejemplifica un caso muy común: tener dos clases que hacen lo mismo pero de diferente manera. P.ej. imagina que Contenedor está implementado usando un array en memoria y OtroContenedor está implementando usando, que sé yo, pongamos un fichero en disco. La funcionalidad (la interfaz) es la misma, lo que varía es la implementación. Es por ello que en programación orientada a objetos decimos que las interfaces son funcionalidades (o comportamientos) y las clases representen implementaciones.

Ahora bien, si dos clases representan dos implementaciones distintas de la misma funcionalidad, es muy enojante (y estúpido) que no las podamos intercambiar. Para que dicho intercambio sea posible C# (y en general cualquier lenguaje orientado a objetos) permite explicitar la interfaz, es decir separar la declaración de la interfaz de su implementación (de su clase). Para ello usamos la palabra clave interface:

interface IContenedor
{
int Quitar();
void Meter(int i);
}

Este código declara una interfaz IContenedor que declara los métodos Quitar y Meter. Fíjate que los métodos no se declaran como public (en una interfaz la visibilidad no tiene sentido, ya que todo es public) y que no se implementan los métodos.

Las interfaces son un concepto más teórico que real. No se pueden crear interfaces. El siguiente código NO compila:

IContenedor c = new IContenedor();
// Error: No se puede crear una interfaz!

Es lógico que NO podamos crear interfaces, ya que si se nos dejara, y luego hacemos c.Quitar()… que método se llamaría si el método Quitar() no está implementado?

Aquí es donde volvemos a las clases: podemos indicar explícitamente que una clase implementa una interfaz, es decir proporciona implementación (código) a todos y cada uno de los métodos (y propiedades) declarados en la interfaz:

class Contenedor : IContenedor
{
public int Quitar() { ... }
public void Meter(int i) { ... }
}

La clase Contenedor declara explícitamente que implementa la interfaz IContenedor. Así pues la clase debe proporcionar implementación para todos los métodos de la interfaz. El siguiente código p.ej. no compila:

class Contenedor : IContenedor
{
public void Meter(int i) { ... }
}
// Error: Y el método Quitar()???

Es por esto que en orientación a objetos decimos que las interfaces son contratos, porque si yo creo la clase la interfaz me obliga a implementar ciertos métodos y si yo uso la clase, la interfaz me dice que métodos puedo llamar.

Y ahora viene lo bueno: Si dos clases implementan la misma interfaz son intercambiables. Dicho de otro modo, en cualquier sitio donde se espere una instancia de la interfaz puede pasarse una instancia de cualquier clase que implemente dicha interfaz.

Podríamos declarar nuestro método foo anterior como sigue:

void foo(IContenedor c)
{
// Cosas con c...
c.Quitar();
c.Meter(10);
}

Fíjate que la clave es que el parámetro de foo está declarado como IContenedor, no como Contenedor o OtroContenedor, con esto indicamos que el método foo() trabaja con cualquier objeto de cualquier clase que implemente IContenedor.

Y ahora, si supones que tanto Contenedor como OtroContenedor implementan la interfaz IContenedor el siguiente código es válido:

Contenedor c = new Contenedor();
foo(c); // Ok. foo espera IContenedor y Contenedor implementa IContenedor
OtroContenedor oc = new OtroContenedor();
foo(oc); // Ok. foo espera IContenedor y OtroContenedor implementa IContenedor
// Incluso esto es válido:
IContenedor ic = new Contenedor();
IContenedor ic2 = new OtroContenedor();

4. ¿Cuando usar interfaces?

En general siempre que tengas, o preveas que puedes tener más de una clase para hacer lo mismo: usa interfaces. Es mejor pecar de exceso que de defecto en este caso. No te preocupes por penalizaciones de rendimiento en tu aplicación porque no las hay.´

No digo que toda clase deba implementar una interfaz obligatoriamente, muchas clases internas no lo implementarán, pero en el caso de las clases públicas (visibles desde el exterior) deberías pensarlo bien. Además pensar en la interfaz antes que en la clase en sí, es pensar en lo que debe hacerse en lugar de pensar en como debe hacerse. Usar interfaces permite a posteriori cambiar una clase por otra que implemente la misma interfaz y poder integrar la nueva clase de forma mucho más fácil (sólo debemos modificar donde instanciamos los objetos pero el resto de código queda igual).

5. Segregación de interfaces

Imagina que tenemos un sistema que debe trabajar con varios vehículos, entre ellos aviones y coches, así que declaramos la siguiente interfaz:

interface IVehiculo
{
void Acelerar(int kmh);
void Frenar();
void Girar(int angulos);
void Despegar();
void Aterrizar();
}

Luego implementamos la clase avión:

class Avion : IVehiculo
{
public void Acelerar(int kmh) { ... }
public void Frenar() { ... }
public void Girar (int angulos) { ... }
public void Despegar() { ... }
public void Aterrizar() { ... }
}

Y luego vamos a por la clase coche… y aquí surge el problema:

class Coche : IVehiculo
{
public void Acelerar(int kmh) { ... }
public void Frenar() { ... }
public void Girar (int angulos) { ... }
public void Despegar() {throw new NotImplementedException("Coches no vuelan"); }
public void Aterrizar(){throw new NotImplementedException("Coches no vuelan"); }
}

La interfaz IVehiculo tiene demasiados métodos y no define el comportamiento de todos los vehículos, dado que no todos los vehículos despegan y aterrizan. En este caso es mejor dividir la interfaz en dos:

interface IVehiculo
{
void Acelerar(int kmh);
void Frenar();
void Girar (int angulos);
}

interface IVehiculoVolador : IVehiculo
{
void Despegar();
void Aterrizar();
}

Fíjate además que IVehiculoVolador deriva de IVehiculo (en orientación a objetos decimos que hay una relación de herencia entre IVehiculoVolador y IVehiculo), eso significa que una clase que implemente IVehiculoVolador debe implementar también IVehiculo forzosamente. Por lo tanto podemos afirmar que todos los vehículos voladores son también vehículos.

Ahora si que la clase Coche puede implementar IVehiculo y la clase Avion puede implementar IVehiculoVolador (y por lo tanto también IVehiculo). Si un método foo() recibe un objeto IVehiculoVolador puede usar métodos tanto de IVehiculoVolador como de IVehiculo:

void foo (IVehiculoVolador vv)
{
vv.Acelerar(10); // Ok. Acelerar es de IVehiculo y IVehiculoVolador deriva de IVehiculo
vv.Despegar(); // Ok. Despegar es de IVehiculoVolador
}

Al reves no! Si un método foo recibe un IVehiculo no puede llamar a métodos de IVehiculoVolador. Lógico: todos los vehículos voladores son vehículos pero al revés no… no todos los vehículos son vehículos voladores!

Siempre que haya segregación no tiene por que haber herencia de interfaces. Imagina el caso de que además de vehículos debemos tratar con Armas de guerra. Tenemos otra interfaz:

interface IArmaDeGuerra
{
void Apuntar();
void Disparar();
}

Ahora podrían existir clases que implementen IArmaDeGuerra como p.ej. una torreta defensiva:

class TorretaDefensiva : IArmaDeGuerra
{
public void Apuntar() { ... }
public void Disparar() { ... }
}

Pero claro… también tenemos vehículos que pueden ser a la vez armas de guerra, p.ej. un tanque! Que hacemos? Ningún problema: una clase puede implementar más de una interfaz a la vez! Para ello debe implementar todos los métodos de todas la interfaces:

class Tanque : IVehiculo, IArmaDeGuerra
{
public void Acelerar(int kmh) { ... }
public void Frenar() { ... }
public void Girar (int angulos) { ... }
public void Apuntar() { ... }
public void Disparar() { ... }
}

Ahora si un método foo() recibe un IVehiculo le puedo pasar un Tanque y si otro método foo2 recibe un IArmaDeGuerra también le puedo pasar un Tanque. O dicho de otro modo, los tanques se comportan como vehículos y como armas de guerra a la vez!

Así pues, es importante segregar bien nuestras interfaces porque en caso contrario vamos a tener dificultades a la hora de implementarlos. La segregación de interfaces es uno de los 5 principios SOLID (concretamente la letra I: interface segregation principle).

Bueno… espero que este post os haya ayudado a comprender mejor que son las interfaces y como usarlas!

Un saludo a todos!

40 comentarios en “[C# Básico] Interfaces”

  1. Wow… Muchas gracias. Super.. Muy claro me ha quedado…
    Según tengo ententido utilizar interfaces es un patrón, no?
    ¿Qué otros patrones se deberían utilizar en nuestros proyectos?

    Te cuento algo, este post y la explicación me cayó como anillo al dedo. Imagínate que estoy haciendo un sitio de Videos. Ahora estoy trabajando con un sólo proveedor de videos, pero es posible que luego hayan otros.

    Lo que hice fue crear en mi modelo una clase Video y unos métodos que “convierten” el video de mi proveedor en mi video. Así cuando hayan otros proveedores lo que haría sería crear nuevos métodos que transformen los videos de los otros proveedores en los mios propios.

    Ya veo que es mucho mejor crear una interfaz y simplemente dentro de cada proveedor implemento sus métodos. Super… Muchas gracias!

    Saludos!

  2. Bravo, me viene de perlas este tipo de artículos. Ya que quieres ideas te propongo el siguiente indice:

    POO: ¿Que es la herencia?
    POO: Cuando un método, cuando una clase?
    SOLID (ya has tocado la I)
    POO: ¿Class o strutc?

    Yo soy uno de lo que también piensa que hay bastante escrito sobre lo más de lo más. Pero que falta la información básica para noobs o un poquito más.

    Mil gracias.

  3. Excelente explicación de Interfaces Eduard,

    Abusando de la opción de hacer peticion de temas basicos de C#, porque no dedicas un post a los delegados, creo que estaria genial hablar de eso.

    Saludos.

  4. Me sumo a la petición:

    POO: ¿Que es la herencia?

    POO: Cuando un método, cuando una clase?

    SOLID (ya has tocado la I)

    POO: ¿Class o strutc?

    saludos y gracias

  5. Hola a todos!

    @Gabriel
    El uso de interfaces más que un patrón en si mismo es una técnica de desarrollo. Un patrón es más una idea que se reutiliza en distintos proyectos. Hay muchos patrones, que van desde lo más simple a lo más complejo.
    Un patrón es cuando dices “hey! este problema me lo encontré una vez y lo solucioné de esta manera” y repites la solución… Dado que hay problemas que son “casi universales” está bien conocer cual es la forma de solucionarlos.
    Es muy posible que estés usando patrones sin siquiera saberlo: si te enfrentas al mismo problema que “toda una generación anterior” de desarrolladores, es muy probable que llegues a la misma solución 🙂

    Ejemplos de patrones, pues hay muchos… Echa un vistazo a http://www.dofactory.com/Patterns/Patterns.aspx

    @Juan, Norberto, manuel
    Me apunto los temas que decís y los iré abordando en futuros posts… voy a etiquetarlos todos como [C# Básico] como éste!

    De todos modos, si queréis ver temas SOLID en más profundidad, os comento que en DotNetMania se está realizando una serie de artículos a cargo de dos bestias pardas como Hadi Hariri y José Miguel Torres, dedicados precisamente a los 5 principios SOLID. Os los recomiendo!!!!

    Un saludo y muchas gracias por vuestros comentarios!!! 😉

  6. Echo en falta que expliques el que se puede hacer esto ….

    ((Interfaz)var).Metodo()

    donde “var” es del tipo Object.

    Pero muy completo y sobre todo muy bien explicado.

  7. Gracias Eduard..
    Intentando pasar mi problema a Interfaces me topé con una situación: ¿Cómo se manejan las variables?
    Especificamente, con lo que te mencioné de mi sitio de Videos.
    Yo tengo mi clave MyVideo donde necesito definir algunas variables propias como un ID que nada que ver con el de mi proveedor (YouTube).
    Pero si ya no voy a trabajar con mi Clase: MyVideo sino con una interfaz, ¿dónde meto el ID y mis otras variables que necesito que no tiene YouTube?
    Muchsa gracia sy saludos!

  8. @jorge

    Lo que comentas (que se llama casting) funcionará solo si var contiene realmente un objeto de una clase que implementa la interfaz. En caso contrario compilará pero dará un error en tiempo de ejecución.
    El casting es un tema más complejo de lo que parece ya que debemos distinguir el tipo de la referencia (de que tipo se ha declarado var) y el tipo del objeto a la que apunta esta referencia (de que clase se creó el objeto que se asignó a var).

    @Gabriel
    Me es dificil ayudarte sin saber tu jerarquía de clases o que interfaces piensas montar.
    Tu interfaz IMyVideo no puede declarar variables PERO SI propiedades, es decir:

    interface IMyVideo
    {
    int Id { get; set;}
    }

    Esto es válido, y declara una interfaz con una propiedad llamada Id, de tipo int.
    Luego puedes hacer una clase que implemente la propiedad. Si usas C# 2.0 o anterior tendrás un código parecido a:

    class YoutubeVideo : IMyVideo
    {
    private int _id;
    public int Id
    {
    get { return _id; }
    set { _id = value; }
    }
    }

    set {} y get {} implementan las funciones de lectura / escritura de la propiedad. En este caso simplemente la propiedad sirve como “acceso público” a una variable privada (pero en set y get puedes poner lo que quieras).

    Usar propiedades es una práctica muy recomendable y de hecho propiedades “triviales” (que sólo sirven para dar acceso público a una variable privada) son tan comunes que C# 3.0 y posteriores lo soportan directamente. Por ello si usas C# 3.0 (Vs2008) o posteriores puedes implementar la interfaz así:

    class YoutubeVideo : IMyVideo
    {
    public int Id { get; set;}
    }

    Este código es EQUIVALENTE al código anterior.

    Un saludo a todos y gracias por vuestros comentarios!! 😉

  9. Amigo muy buen post, queria saber si de pronto en un nuevo tema puedes hablar de los constructores de una clase, por ejemplo cuando se usa el diseñador de clases, hay propiedad y campo, cual es la diferencia entre estos, por ejemplo en una clase de clientes he visto que ponen muchos algo como esto

    private _codigo;

    public int Codigo

    {

    get { return _codigo; }

    set { _codigo = value; }

    }

    Para que se hace esto y porque no se puede directo trabajar solo con
    public int Codigo {get;Set;};
    Esto es basico pero que no lo tengo muy claro, espero puedas aclarar este tema con un post.

    Saludos

  10. @Fernando
    Voy a tratar el tema en más detalle en un futuro post, pero referente a tu comentario.

    Ambas porciones de código que pones son equivalentes, la primera es en C# 2.0 (VS2005) o anterior y el otro es C# 3.0 o posterior (VS2008).
    Ojo! El código es equivalente SIEMPRE QUE SE ENCUENTRE EN UNA CLASE. Si está en una interfaz, entonces solo puede usarse la 2a versión, ya que lo que se está haciendo es declarar una propiedad de lectura/escritura llamada Código.

    Un saludo y muchas gracias por tu comentario!!!

  11. Hola,

    Hace poco escribiste otro artículo en el que explicabas un problema originado por usar directamente una clase en lugar de su interfaz (Usa las interfaces… que para eso están!) y con con lo que sé sobre interfaces y clases la verdad es que no se ver el problema.

    Sin querer abusar y aprovechando que estás escribiendo sobre interfaces te agradecería mucho que nos explicaras el porqué del problema.

    Muchas gracias por tus artículos, si siempre son interesantes estos además nos pueden ser a algunos de mucha ayuda.

    Salud 🙂

  12. @Jose
    El problema que comentaba en el post que mencionas se debía básicamente al uso de COM, pero encontré el tema interesante debido a que en internet he visto muchos (demasiados) ejemplos usando directamente las clases COM en lugar de los interfaces COM asociados.

    Aunque tecnológicamente COM difiere mucho de .NET, las ideas básicas son las mismas (y es que siempre son las mismas): las interfaces encapsulan un comportamiento y las clases una implementación concreta.
    Imagina que yo tengo un método que te devuelve un objeto de tipo IA donde IA es una interface. El método puede estar declarado como:

    IA Foo() { … }

    Tu *a lo mejor* sabes que realmente lo que devuelve es un objeto de una clase A, que implementa IA, de forma que a lo mejor haces esto:

    A a = (A)Foo();

    Nota que el código “ya se ve raro”, dado que debes realizar casting sobre el valor de retorno de Foo para “convertirlo” a un objeto de A. Esta conversión, en el fondo no hace nada, dado que Foo() devuelve ya un objeto de tipo A.
    Ahora bien, si algun dia, yo cambio el método Foo() para que en lugar de A devuelva *otra* clase llamada A2 que también implemente IA tu llamada:

    A a = (A)Foo(); // patapuuuuum!

    … cascará, ya que estás intentando convertir un objeto A2 a un objeto A y aunque tanto A como A2 implementan IA, no “tienen nada que ver” entre ellas y por lo tanto esta conversión da error (en run-time).

    Es normal que veas este ejemplo estúpido: para que vas a realizar una conversión de un método que YA devuelve IA? No tiene ningún sentido y realmente nunca harás esto. Simplemente harás:

    IA a = Foo();

    Es decir, usarás la interfaz. Ahora da igual que Foo() devuelva un A, un A2 o lo que sea que implemente IA: tu código funciona.

    Lo ves lógico, verdad?

    Pues bien, mucha gente cuando programa contra objetos COM, no sigue este proceder… Hay “cierta excusa” debido a dos razones:

    1) Los métodos COM suelen devolver siempre “object” por lo que una conversión siempre es necesaria
    2) El versionado de interfaces COM es un poco liado… lo que hace que una clase COM termine implementando n interfaces

    El punto (1) es la clave. Cuando añado una referencia COM, VS genera un wrapper en C#, en el cual la mayoría de métodos devuelven “object” (eso es debido a los intríngulis técnicos de COM). Así pues si tu llamas a un método FooCom así:

    object o = FooCom();

    Te encontrarás que luego con “o” no puedes hacer nada, ya que es un object… así que lo que se hace es ir a la documentación del método y ver que tipo COM devuelve realmente el método… y realizar un cast:

    ClaseCom co = (ClaseCom)FooCom();

    Y el error está en realizar el casting convirtiendo a ClaseCom, en lugar de IClaseCom que también existe (el wrapper de VS genera tanto las clases como las interfaces). Si realizamos el casting contra la clase es cuando pueden surgir problemas: dos máquinas distintas pueden tener versiones distintas de la misma DLL COM y una puede devolver ClaseCom y la otra ClaseComV2… Si ejecutas el código que usa ClaseCom en el ordenador cuya DLL COM devuelve ClaseComV2 es cuando te da el error. Lo correcto es usar la interfaz COM:

    IClaseCom ico = (IClaseCom)FooCom();

    No se si te he ayudado o te he liado un poco más… :S

    Muchas gracias por tu comentario!!! 😉

  13. Me parece muy bueno el post y te ánimo a que sigas escribiendo artículos bajó el tema de [C# básico]. Yo apenas comenzé con este lenguaje enfocandome a la programación sobre dispositivos móviles, asi que si algun día puedes escribir un poco al respecto te lo agradecería.

  14. Hola de nuevo

    muchas gracias por la explicación, está clarísima, de hecho en el artículo ya lo explicas lo que pasa es que uno es un poco duro y no supe ver que era lo mismo 🙂

    Lo que me liaba es que al no saber que es realmente (o internamente) una interfaz se me sale un poco de los esquemas el que las interfaces se puedan pasar como parámetros a un método o puedan ser el resultado de una función y me quedé con la idea básica de que simplemente definen unas funcionalidades que las clases que las implementen han de cumplir obligatoriamente.

    Muchas gracias de nuevo por tu explicación y por tu tiempo, me voy a leer el artículo sobre la herencia 🙂

    Salud

  15. @Jose
    Me alegro que la explicación haya servido para aclararte conceptos… para eso estamos!!! 😉

    @alexpardox
    Pues poco te puedo contar sobre programación con móviles, porque salvo algunas pruebas con Compact Framework (que está agonizando) apenas he hecho nada… Tengo intención de meterme con Android y mirarme el SDK de iPhone algun dia de esos… en cambio Windows Phone 7 me deja frío, muy frio… veremos 🙂
    Por aquí en geeks hay gente que domina bastante el tema de móviles… me vienen a la cabeza José Miguel Torres, un crack de Windows Mobile y Eugenio Estrada que está ahora dándole caña a Android… 😉

    Un saludo y gracias por vuestros comentarios, de verdad!!!

  16. @Gisela
    Jejjeee… 🙂
    Pues ahora mismo no recuerdo exactamente donde lo vi… diría que de una charla del maestro Hadi Hariri pero no estoy del todo seguro… La edad (y el alcohol :p) hacen estragos en mi mente 😛

    Un saludo!!! 😉

  17. Muy bueno el post!

    Tengo una consulta, si puedes responderme: no termino de entender cuando usar interfaces y cuando herencia.
    Porque con el ejemplo de los vehiculos puede hacerse con herencia, aunque no la parte del tanque (vehiculo y arma).
    Entonces, solo se deben usar interfaces cuando quiero tener herencia multiple? O conviene usar interfaces siempre por escalabilidad?

    Saludos!

  18. @Ezequiel
    Interfaces y herencia no son incompatibles, no se trata de usar uno u otro, puedes (y deberías) usar ambas…

    Interfaces siempre para separar la definición del comportamiento (interfaz) de la implementación (clase)
    Herencia cuando una clase hereda de otra para reimplementar (modificar) y/o añadir comportamiento a una clase base.

    Lo que comentas de los vehículos, tienes razón, puede hacerse con herencia… pero que es lo que haces con herencia? Pues implementar las interfaces que expuse en el post!

    Es decir, en algún momento tendrás una (o más de una, pero da igual) clase que implementa IVehiculo:

    class MiVehiculo : IVehiculo { … }

    Y luego podrás tener una clase que implemente IVehiculoVolador Y A LA VEZ que herede de MiVehiculo:

    class PeazoAvion : MiVehiculo, IVehiculoVolador { … }

    En la clase PeazoAvion debes implementar los métodos de IVehciuloVolador, teniendo en cuenta que la clase base (MiVehiculo) ya implementa algunos de dichos métodos (en concreto los que se corresponden a IVehiculo).

    No se si me he explicado bien… 🙂

    Un saludo y gracias por tu comentario!

  19. Excelente explicación, en varias páginas estuve buscando una explicación así y la verdad es que esta es la primera que encuentro donde se define bien lo que es una interfaz, es una explicación muya clara y concisa… muchas gracias…

  20. gran ejemplo, de hecho ya forma parte de mis favoritos incluso por la pedagogía usada para entender de manera clara en los ejemplos, sin embargo me surge una duda al tener una clase con un delegado y querer llevar este a una interfaz pues es la clase base para WCF.

    Estoy tratando de armar la analogía del ejemplo con un servicio de WCF sin embargo la clase que deseo colocar en WCF posee dos delegados y deseaba saber como llevarlos a la clase o interfaz si fuera el caso. Vi el artículo referente a delegados, muy bueno por cierto, pero hago la pregunta en este de interfaces pues la duda es saber si lo dejo en la clase o lo llevo a la interfaz, en caso de llevarlo a la interfaz saber cómo hacerlo.

    Gracias a saludos.

  21. @phito

    No puedo ayudarte mucho en WCF, pero sobre el tema que comentas de los delegados y las interfaces… No hay problema en que una interfaz declare un delegado:

    delegate int MyDelegate (int i);
    interface IFoo
    {
    MyDelegate Del { get;}
    }

    Declaro el delegate “MyDelegate” y luego una interfaz llamada IFoo con una propiedad Del cuyo tipo es MyDelegate.

    Ahora puedo implementar esta interfaz, como yo quiera. P.ej:

    class Foo : IFoo
    {
    public MyDelegate Del { get; private set; }
    public Foo()
    {
    this.Del = new MyDelegate(x => x + 1);
    }
    }

    La clase Foo implementa IFoo, y asigna la propiedad Del (fíjate que el set es privado puesto que IFoo sólo obliga a que el set sea público) a una lambda expression que devuelve el valor recibido +1. Esa asignación a la lambda es correcta porque MyDelegate es un delegado a funciones que reciban int y devuelvan int, y eso es compatible con la lambda expression (recibe un int (x) y devuelve un int (x+1)).

    Finalmente puedo crear un objeto Foo y llamar a su delegado:

    IFoo foo = new Foo();
    int ret = foo.Del(10); // ret valdrá 11

    Y listos!

    Como puedes ver no hay ningún problema en combinar delegados e interfaces!

    Un saludo!

  22. Gracias Eduard no tenía los delegados fuera de la clase y por ende fallaba, gracias nuevamente por la explicación.

    Quizás algo de WCF sería interesante, a lo mejor siguiendo el esquema de C# Básico, algo como WCF Básico.

  23. Gracias men muy pero muy claro …… he buscado demaciado y este es el mejor post ….. excelente men felicitaciones …. saludes desde Colombia ….

  24. Barbaro, muy buen post!!, me he sacado las dudas que en ningun otro lado me pude sacar!. Muchisimas gracias! esta muy claro todo.

  25. Gracias!

    La verdad que repasar los conceptos basicos de vez en cuando esta bastante bien, para no nublarte la mente con tanto Framework ni apis

  26. El ejemplo esta bien pero no hizo un ejemplo completo con el método main.
    megustaria un ejemplo usando base de datos puedes hacerlo te lo agradecería

  27. Hola Edward,

    Muchas gracias, me queda muy claro ahora el uso de las Interfaces, exelente explicación y ejemplificación. Voy a leer más artículos tuyos por que me encantaron!

    Un saludo desde Colombia!

  28. Hola. Antes que nada te felicito por el post, me ha quedado clarísimo, ya que lo que me faltaba eran conceptos y en todos lados te explican como se implementa, y para que sirve, pero sin saber cual es la real importancia y porque deberias usarlas.

    Mi consulta es qué pasa con la sobrecarga de métodos?, puedo declararlos en la interface y luego implementar el que necesite o como deberia proceder en ese caso si los métodos aceptan diferentes parámetros?

    1. Hola Rodrigo,
      Una interfaz puede declarar sobrecargas. Puedes tener el método Foo() y el método Foo(int i) en la interfaz.
      Y en la clase debes implementar ambos (NO puedes implementar solo uno).

      Si tu interfaz define Foo() y tu clase “necesita implementar” Foo(int i) entonces tu clase no implementa tu interfaz 😉

      Saludos!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *