Nota
O acceso a esta páxina require autorización. Pode tentar iniciar sesión ou modificar os directorios.
O acceso a esta páxina require autorización. Pode tentar modificar os directorios.
Sugerencia
¿No está familiarizado con el desarrollo de software? Comience primero con los tutoriales de introducción . Encontrará interfaces una vez que necesite definir el comportamiento compartido entre tipos no relacionados.
¿Competente en otro idioma? Las interfaces de C# son similares a las interfaces de Java o protocolos de Swift. Revise la sección de implementación explícita para patrones propios de C#.
Una interfaz define un contrato: un grupo de métodos, propiedades, eventos e indizadores relacionados que un class o un struct deben implementar. Las interfaces permiten que un solo tipo implemente varios contratos, lo que es importante porque C# no admite varias herencias de clases. Las estructuras no pueden heredar de otras estructuras o clases, por lo que las interfaces son la única manera de agregar un comportamiento compartido entre los tipos de estructura.
En el ejemplo siguiente se declara una interfaz y una clase que la implementa:
interface IEquatable<T>
{
bool Equals(T obj);
}
public class Car : IEquatable<Car>
{
public string? Make { get; set; }
public string? Model { get; set; }
public string? Year { get; set; }
public bool Equals(Car? car) =>
car is not null &&
(Make, Model, Year) == (car.Make, car.Model, car.Year);
}
Cualquier clase o estructura que implemente IEquatable<T> debe proporcionar un Equals método que coincida con la firma de la interfaz. Puede contar con que cualquier implementación IEquatable<T> admitirá la comparación de igualdad, independientemente del tipo concreto. Esa previsibilidad es el valor principal de las interfaces.
Declarar una interfaz
Defina una interfaz con la interface palabra clave . Por convención, los nombres de interfaz comienzan por un capital I:
interface ILogger
{
void Log(string message);
string Name { get; }
}
Las interfaces pueden contener métodos, propiedades, eventos e indizadores. Una interfaz no puede contener campos de instancia, constructores de instancias ni finalizadores. Los miembros son public de forma predeterminada. Puede especificar otros modificadores de accesibilidad cuando sea necesario. Por ejemplo, use internal para los miembros que no deben ser visibles fuera del ensamblaje.
Implementación de una interfaz
Una clase o estructura enumera las interfaces que implementa después de dos puntos en su declaración. La clase debe proporcionar una implementación para cada miembro declarado en la interfaz:
public class ConsoleLogger : ILogger
{
public string Name => "Console";
public void Log(string message) =>
Console.WriteLine($"[{Name}] {message}");
}
public class FileLogger : ILogger
{
public string Name => "File";
public void Log(string message)
{
// In a real app, write to a file
Console.WriteLine($"[{Name}] Writing to file: {message}");
}
}
Una clase puede implementar varias interfaces, separadas por comas. Debe proporcionar implementaciones para todos los miembros de cada interfaz que muestra.
Implementación explícita
A veces, debe implementar un miembro de interfaz sin convertirlo en parte de la API pública de la clase. La implementación explícita vincula el miembro con el nombre de la interfaz. El miembro solo es accesible a través de una variable del tipo de interfaz:
interface IMetric
{
double GetDistance(); // Returns meters
}
interface IImperial
{
double GetDistance(); // Returns feet
}
public class Runway(double meters) : IMetric, IImperial
{
// Explicit implementation for IMetric
double IMetric.GetDistance() => meters;
// Explicit implementation for IImperial
double IImperial.GetDistance() => meters * 3.28084;
}
La implementación explícita es útil cuando dos interfaces declaran miembros con el mismo nombre o cuando se desea mantener limpia la superficie pública de la clase. Para obtener más información, consulte Implementación explícita de la interfaz.
Herencia de interfaz
Las interfaces pueden heredar de una o varias interfaces. Una clase que implementa una interfaz derivada debe implementar todos los miembros de la interfaz derivada y todas sus interfaces base:
interface IDrawable
{
void Draw();
}
interface IShape : IDrawable
{
double Area { get; }
}
public class Circle(double radius) : IShape
{
public double Area => Math.PI * radius * radius;
public void Draw() =>
Console.WriteLine($"Drawing circle with area {Area:F2}");
}
Una clase que implementa IShape se puede convertir implícitamente en IDrawable, porque IShape hereda de ella.
Interfaces frente a clases abstractas
Tanto las interfaces como las clases abstractas definen contratos que deben cumplir los tipos derivados.
- Use una clase abstracta cuando los tipos relacionados compartan estado (campos), constructores o miembros no públicos. Las clases abstractas permiten evolucionar una jerarquía agregando nuevos miembros con comportamiento predeterminado sin interrumpir los tipos derivados existentes.
- Use una interfaz cuando un tipo necesite cumplir un contrato que se divide en jerarquías no relacionadas o cuando necesite implementar varios contratos. Las interfaces no pueden declarar campos o constructores de instancia, por lo que son más adecuados para agregar funcionalidades a tipos que ya tienen una clase base. En escenarios avanzados, las interfaces también admiten implementaciones de miembros predeterminadas.
Una clase solo puede heredar de una clase base, pero puede implementar varias interfaces. Esa distinción a menudo convierte las interfaces en la mejor opción para definir las funcionalidades que se cortan entre jerarquías de tipos.
Trabajar con interfaces internas
Normalmente, puede implementar una interfaz interna con miembros públicos, siempre que todos los tipos de la firma de interfaz sean accesibles públicamente. Cuando una interfaz utiliza tipos internos en las signaturas de sus miembros, es necesario usar la implementación explícita porque el miembro que implementa no puede ser público al exponer tipos internos.
internal class InternalConfiguration
{
public string Setting { get; set; } = "";
}
internal interface ILoggable
{
void Log(string message);
}
internal interface IConfigurable
{
void Configure(InternalConfiguration config);
}
public class ServiceImplementation : ILoggable, IConfigurable
{
// Implicit implementation: ILoggable uses only public types in its signature
public void Log(string message) =>
Console.WriteLine($"Log: {message}");
// Explicit implementation: IConfigurable uses internal types
void IConfigurable.Configure(InternalConfiguration config) =>
Console.WriteLine($"Configured with: {config.Setting}");
}
En el ejemplo anterior, IConfigurable usa un tipo InternalConfiguration interno en su firma de método.
ServiceImplementation utiliza la implementación explícita para ese miembro. Por el contrario, ILoggable solo usa tipos públicos (string) en su firma y se puede implementar implícitamente.
Miembros de interfaz predeterminados y miembros abstractos estáticos
Las interfaces admiten dos características avanzadas que van más allá de los contratos básicos:
- Los miembros de interfaz predeterminados permiten que una interfaz proporcione un cuerpo del método. Los tipos de implementación heredan la implementación predeterminada y, opcionalmente, pueden invalidarlo. Para obtener más información, vea Métodos de interfaz predeterminados.
- Los miembros abstractos estáticos requieren tipos de implementación para proporcionar un miembro estático, lo que resulta útil para definir contratos de operador o patrones de fábrica. Para obtener más información, consulte miembros abstractos estáticos en interfaces.
Ambas características se tratan en el artículo sobre las interfaces de la referencia del lenguaje. La mayoría del uso diario de la interfaz implica la declaración e implementación de patrones descritos anteriormente en este artículo.
Resumen de interfaces
- Una interfaz define un contrato de métodos, propiedades, eventos e indexadores.
- Una clase o estructura que implementa una interfaz debe proporcionar implementaciones para todos los miembros declarados (a menos que la interfaz proporcione una implementación predeterminada).
- No se puede instanciar una interfaz directamente.
- Una clase o estructura puede implementar varias interfaces. Una clase puede heredar una clase base y también implementar una o varias interfaces.
- Los nombres de interfaz empiezan convencionalmente por
I.