interface (Referencia de C#)
Una interfaz define un contrato. Cualquier class
, record
o struct
que implemente ese contrato debe proporcionar una implementación de los miembros definidos en la interfaz. Una interfaz puede definir una implementación predeterminada de miembros. También puede definir miembros static
para proporcionar una única implementación de funcionalidad común. A partir de C# 11, una interfaz puede definir miembros static abstract
o static virtual
para declarar que un tipo de implementación debe proporcionar los miembros declarados. Normalmente, los métodos static virtual
declaran que una implementación debe definir un conjunto de operadores sobrecargados.
En el ejemplo siguiente, la clase ImplementationClass
debe implementar un método denominado SampleMethod
que no tiene ningún parámetro y devuelve void
.
Para obtener más información y ejemplos, vea Interfaces.
Una interfaz de nivel superior, una declarada en un espacio de nombres, pero no anidada dentro de otro tipo, se puede declarar public
o internal
. El valor predeterminado es internal
. Las declaraciones de interfaz anidadas, declaradas dentro de otro tipo, se pueden declarar mediante cualquier modificador de acceso.
Los miembros de interfaz sin una implementación no pueden incluir un modificador de acceso. Los miembros con una implementación predeterminada pueden incluir cualquier modificador de acceso.
Interfaz de ejemplo
interface ISampleInterface
{
void SampleMethod();
}
class ImplementationClass : ISampleInterface
{
// Explicit interface member implementation:
void ISampleInterface.SampleMethod()
{
// Method implementation.
}
static void Main()
{
// Declare an interface instance.
ISampleInterface obj = new ImplementationClass();
// Call the member.
obj.SampleMethod();
}
}
Una interfaz puede ser un miembro de un espacio de nombres o una clase. Una declaración de interfaz puede contener declaraciones (firmas sin ninguna implementación) de los miembros siguientes:
Miembros de interfaz predeterminados
Normalmente, estas declaraciones de miembros anteriores no contienen ningún cuerpo. Un miembro de interfaz puede declarar un cuerpo. Los cuerpos miembros de una interfaz son la implementación predeterminada. Los miembros con cuerpos permiten que la interfaz proporcione una implementación "predeterminada" de las clases y las estructuras que no proporcionan una implementación de invalidación.
Importante
Agregar miembros de interfaces predeterminados obliga a cualquier ref struct
que implemente la interfaz a agregar una declaración explícita de ese miembro.
Una interfaz puede incluir:
- Constantes
- Operadores
- Constructor estático.
- Tipos anidados
- Campos, métodos, propiedades, indizadores y eventos estáticos.
- Declaraciones de miembros con la sintaxis de implementación de interfaz explícita.
- Modificadores de acceso explícitos (el acceso predeterminado es
public
).
Miembros abstractos y virtuales estáticos
A partir de C# 11, una interfaz puede declarar miembros static abstract
y static virtual
para todos los tipos de miembros excepto los campos. Las interfaces pueden declarar que los tipos de implementación deben definir operadores u otros miembros estáticos. Esta característica permite a los algoritmos genéricos especificar el comportamiento como un número. Puede ver ejemplos de los tipos numéricos en el entorno de ejecución de .NET, como System.Numerics.INumber<TSelf>. Estas interfaces definen operadores matemáticos comunes implementados por muchos tipos numéricos. El compilador debe resolver las llamadas a los métodos static virtual
y static abstract
en tiempo de compilación. Los métodos static virtual
y static abstract
declarados en interfaces no tienen un mecanismo de distribución en tiempo de ejecución análogo a los métodos virtual
o abstract
declarados en clases. En su lugar, el compilador usa la información de tipos disponible en tiempo de compilación. Por lo tanto, los métodos static virtual
se declaran casi exclusivamente en interfaces genéricas. Además, la mayoría de las interfaces que declaran métodos static virtual
o static abstract
declaran que uno de los parámetros de tipo debe implementar la interfaz declarada. Por ejemplo, la interfaz INumber<T>
declara que T
debe implementar INumber<T>
. El compilador usa el argumento de tipo para resolver llamadas a los métodos y operadores declarados en la declaración de interfaz. Por ejemplo, el tipo int
implementa INumber<int>
. Cuando el parámetro de tipo T
denota el argumento de tipo int
, se invocan los miembros static
declarados en int
. Como alternativa, cuando double
es el argumento type, se invocan los miembros static
declarados en el tipo double
.
Importante
La distribución de métodos para los métodos static abstract
y static virtual
declarados en interfaces se resuelve mediante el tipo de tiempo de compilación de una expresión. Si el tipo en tiempo de ejecución de una expresión se deriva de un tipo de tiempo de compilación diferente, se llamará a los métodos estáticos en el tipo base (tiempo de compilación).
Puede probar esta característica trabajando con el tutorial sobre miembros abstractos estáticos en interfaces.
Herencia de interfaz
Es posible que las interfaces no contengan estado de instancia. Aunque los campos estáticos ahora están permitidos, los campos de instancia no se permiten en las interfaces. Las propiedades automáticas de instancia no se admiten en las interfaces, ya que declararían de forma implícita un campo oculto. Esta regla tiene un efecto sutil en las declaraciones de propiedad. En una declaración de interfaz, el código siguiente no declara una propiedad implementada automáticamente como en o class
struct
. En su lugar, declara una propiedad que no tiene una implementación predeterminada pero que se debe implementar en cualquier tipo que implemente la interfaz:
public interface INamed
{
public string Name {get; set;}
}
Una interfaz puede heredar de una o varias interfaces base. Cuando una interfaz hereda de otra interfaz, el tipo que implementa la interfaz derivada debe implementar todos los miembros de las interfaces base, así como los declarados en la interfaz derivada, como se muestra en el código siguiente:
public interface I1
{
void M1();
}
public interface I2 : I1
{
void M2();
}
public class C : I2
{
// implements I1.M1
public void M1() { }
// implements I2.M2
public void M2() { }
}
Cuando una interfaz invalida un método implementado en una interfaz base, debe usar la sintaxis de implementación de interfaz explícita.
Cuando una lista de tipos base contiene una clase e interfaces base, la clase base debe aparecer primero en la lista.
Una clase que implementa una interfaz puede implementar explícitamente miembros de esa interfaz. A un miembro implementado explícitamente solo se puede tener acceso mediante una instancia de la interfaz, y no mediante una instancia de la clase. Además, solo se puede acceder a los miembros de interfaz predeterminados a través de una instancia de la interfaz.
Para obtener más información sobre la implementación de interfaz explícita, vea Implementación de interfaz explícita.
Implementación de interfaz de ejemplo
En el ejemplo siguiente se muestra la implementación de una interfaz. En este ejemplo, la interfaz contiene la declaración de propiedad y la clase contiene la implementación. Cualquier instancia de una clase que implemente IPoint
tiene las propiedades de entero x
e y
.
interface IPoint
{
// Property signatures:
int X { get; set; }
int Y { get; set; }
double Distance { get; }
}
class Point : IPoint
{
// Constructor:
public Point(int x, int y)
{
X = x;
Y = y;
}
// Property implementation:
public int X { get; set; }
public int Y { get; set; }
// Property implementation
public double Distance =>
Math.Sqrt(X * X + Y * Y);
}
class MainClass
{
static void PrintPoint(IPoint p)
{
Console.WriteLine("x={0}, y={1}", p.X, p.Y);
}
static void Main()
{
IPoint p = new Point(2, 3);
Console.Write("My Point: ");
PrintPoint(p);
}
}
// Output: My Point: x=2, y=3
Especificación del lenguaje C#
Para más información, consulte la sección Interfaces de la especificación del lenguaje C#, la especificación de características para C# 8: miembros de interfaz predeterminados y la especificación de características para C# 11: miembros abstractos estáticos en interfaces.