Interfaces: definir el comportamiento de varios tipos

Una interfaz contiene las definiciones de un grupo de funcionalidades relacionadas que una class o una struct no abstracta deben implementar. Una interfaz puede definir métodos static, que deben tener una implementación. Una interfaz puede definir una implementación predeterminada de miembros. Una interfaz no puede declarar datos de instancia, como campos, propiedades implementadas automáticamente o eventos similares a las propiedades.

Mediante las interfaces puede incluir, por ejemplo, un comportamiento de varios orígenes en una clase. Esta capacidad es importante en C# porque el lenguaje no admite la herencia múltiple de clases. Además, debe usar una interfaz si desea simular la herencia de estructuras, porque no pueden heredar de otra estructura o clase.

Para definir una interfaz, deberá usar la palabra clave interface, tal y como se muestra en el ejemplo siguiente.

interface IEquatable<T>
{
    bool Equals(T obj);
}

El nombre de una interfaz debe ser un nombre de identificador de C# válido. Por convención, los nombres de interfaz comienzan con una letra I mayúscula.

Cualquier clase o estructura que implementa la interfaz IEquatable<T> debe contener una definición para un método Equals que coincida con la firma que la interfaz especifica. Como resultado, puede contar con una clase que implementa IEquatable<T> para contener un método Equals con el que una instancia de la clase puede determinar si es igual a otra instancia de la misma clase.

La definición de IEquatable<T> no facilita ninguna implementación para Equals. Una clase o estructura puede implementar varias interfaces, pero una clase solo puede heredar de una sola clase.

Para obtener más información sobre las clases abstractas, vea Clases y miembros de clase abstractos y sellados (Guía de programación de C#).

Las interfaces pueden contener propiedades, eventos, indizadores o métodos de instancia, o bien cualquier combinación de estos cuatro tipos de miembros. Las interfaces pueden contener constructores estáticos, campos, constantes u operadores. A partir de C# 11, los miembros de interfaz que no son campos pueden ser static abstract. Una interfaz no puede contener campos de instancia, constructores de instancias ni finalizadores. Los miembros de interfaz son públicos de forma predeterminada y se pueden especificar explícitamente modificadores de accesibilidad, como public, protected, internal, private, protected internal o private protected. Un miembro private debe tener una implementación predeterminada.

Para implementar un miembro de interfaz, el miembro correspondiente de la clase de implementación debe ser público, no estático y tener el mismo nombre y firma que el miembro de interfaz.

Nota

Cuando una interfaz declara miembros estáticos, un tipo que implementa esa interfaz también puede declarar miembros estáticos con la misma firma. Los miembros son distintos y se identifican de forma única mediante el tipo que declara el miembro. El miembro estático declarado en un tipo no reemplaza el miembro estático que se declara en la interfaz.

Una clase o estructura que implementa una interfaz debe proporcionar una implementación para todos los miembros declarados sin una implementación predeterminada proporcionada por la interfaz. Sin embargo, si una clase base implementa una interfaz, cualquier clase que se derive de la clase base hereda esta implementación.

En el siguiente ejemplo se muestra una implementación de la interfaz IEquatable<T>. La clase de implementación Car debe proporcionar una implementación del método Equals.

public class Car : IEquatable<Car>
{
    public string? Make { get; set; }
    public string? Model { get; set; }
    public string? Year { get; set; }

    // Implementation of IEquatable<T> interface
    public bool Equals(Car? car)
    {
        return (this.Make, this.Model, this.Year) ==
            (car?.Make, car?.Model, car?.Year);
    }
}

Las propiedades y los indizadores de una clase pueden definir descriptores de acceso adicionales para una propiedad o indizador que estén definidos en una interfaz. Por ejemplo, una interfaz puede declarar una propiedad que tenga un descriptor de acceso get. La clase que implementa la interfaz puede declarar la misma propiedad con un descriptor de acceso get y set. Sin embargo, si la propiedad o el indizador usan una implementación explícita, los descriptores de acceso deben coincidir. Para obtener más información sobre la implementación explícita, vea Implementación de interfaz explícita y Propiedades de interfaces.

Las interfaces pueden heredar de una o varias interfaces. La interfaz derivada hereda los miembros de sus interfaces base. Una clase que implementa una interfaz derivada debe implementar todos los miembros de esta, incluidos los de las interfaces base. Esa clase puede convertirse implícitamente en la interfaz derivada o en cualquiera de sus interfaces base. Una clase puede incluir una interfaz varias veces mediante las clases base que hereda o mediante las interfaces que otras interfaces heredan. Sin embargo, la clase puede proporcionar una implementación de una interfaz solo una vez y solo si la clase declara la interfaz como parte de la definición de la clase (class ClassName : InterfaceName). Si la interfaz se hereda porque se heredó una clase base que implementa la interfaz, la clase base proporciona la implementación de los miembros de la interfaz. Sin embargo, la clase derivada puede volver a implementar cualquier miembro de la interfaz virtual, en lugar de usar la implementación heredada. Cuando las interfaces declaran una implementación predeterminada de un método, cualquier clase que las implemente heredará la implementación correspondiente (deberá convertir la instancia de clase al tipo de interfaz para acceder a la implementación predeterminada en el miembro de la interfaz).

Una clase base también puede implementar miembros de interfaz mediante el uso de los miembros virtuales. En ese caso, una clase derivada puede cambiar el comportamiento de la interfaz reemplazando los miembros virtuales. Para obtener más información sobre los miembros virtuales, vea Polimorfismo.

Resumen de interfaces

Una interfaz tiene las propiedades siguientes:

  • En las versiones de C# anteriores a la 8.0, una interfaz es como una clase base abstracta con solo miembros abstractos. Cualquier clase o estructura que implemente la interfaz debe implementar todos sus miembros.
  • A partir de la versión 8.0 de C#, una interfaz puede definir implementaciones predeterminadas para algunos o todos sus miembros. Una clase o estructura que implemente la interfaz no tiene que implementar los miembros que tengan implementaciones predeterminadas. Para obtener más información, vea Métodos de interfaz predeterminados.
  • No se puede crear una instancia de una interfaz directamente. Sus miembros se implementan por medio de cualquier clase o estructura que implementa la interfaz.
  • Una clase o estructura puede implementar varias interfaces. Una clase puede heredar una clase base y también implementar una o varias interfaces.