Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Las interfaces especifican conjuntos de miembros relacionados que implementan otras clases.
Sintaxis
// Interface declaration:
[ attributes ]
type [accessibility-modifier] interface-name =
[ interface ] [ inherit base-interface-name ...]
abstract member1 : [ argument-types1 -> ] return-type1
abstract member2 : [ argument-types2 -> ] return-type2
...
[ end ]
// Implementing, inside a class type definition:
interface interface-name with
member self-identifier.member1argument-list = method-body1
member self-identifier.member2argument-list = method-body2
// Implementing, by using an object expression:
[ attributes ]
let class-name (argument-list) =
{ new interface-name with
member self-identifier.member1argument-list = method-body1
member self-identifier.member2argument-list = method-body2
[ base-interface-definitions ]
}
member-list
Observaciones
Las declaraciones de interfaz se asemejan a las declaraciones de clase, excepto que no se implementa ningún miembro. En su lugar, todos los miembros son abstractos, como se indica en la palabra clave abstract. No se proporciona un cuerpo del método para los métodos abstractos. F# no puede definir una implementación de método predeterminada en una interfaz, pero es compatible con las implementaciones predeterminadas definidas por C#. Las implementaciones predeterminadas que usan la default palabra clave solo se admiten al heredar de una clase base que no sea de interfaz.
La accesibilidad predeterminada para las interfaces es public.
Opcionalmente, puede asignar un nombre a cada parámetro de método mediante la sintaxis normal de F#:
type ISprintable =
abstract member Print: format: string -> unit
En el ejemplo anterior ISprintable , el Print método tiene un único parámetro del tipo string con el nombre format.
Hay dos maneras de implementar interfaces: mediante expresiones de objeto y mediante tipos. En cualquier caso, la expresión de tipo o objeto proporciona cuerpos de método para métodos abstractos de la interfaz. Las implementaciones son específicas de cada tipo que implementa la interfaz. Por lo tanto, los métodos de interfaz en diferentes tipos pueden ser diferentes entre sí.
Las palabras clave interface y end, que marcan el inicio y el final de la definición, son opcionales cuando se usa la sintaxis ligera. Si no usa estas palabras clave, el compilador intenta deducir si el tipo es una clase o una interfaz mediante el análisis de las construcciones que usa. Si define un miembro o usa otra sintaxis de clase, el tipo se interpreta como una clase.
El estilo de codificación de .NET consiste en comenzar todas las interfaces con una mayúscula I.
Puede especificar varios parámetros de dos maneras: F#-style y . Estilo NET. Ambos compilarán el mismo modo para los consumidores de .NET, pero F#-style obligará a los autores de llamada de F# a usar la aplicación de parámetros de estilo F#y . El estilo NET forzará a los autores de llamadas de F# a usar la aplicación de argumentos tupled.
type INumericFSharp =
abstract Add: x: int -> y: int -> int
type INumericDotNet =
abstract Add: x: int * y: int -> int
Implementación de interfaces mediante tipos de clase
Puede implementar una o varias interfaces en un tipo de clase mediante la interface palabra clave , el nombre de la interfaz y la with palabra clave , seguidas de las definiciones de miembro de interfaz, como se muestra en el código siguiente.
type IPrintable =
abstract member Print: unit -> unit
type SomeClass1(x: int, y: float) =
interface IPrintable with
member this.Print() = printfn "%d %f" x y
Las implementaciones de interfaz se heredan, por lo que las clases derivadas no necesitan volver a implementarlas.
Definir interfaces vacías o de marcador
Las interfaces vacías, también conocidas como interfaces de marcador, se pueden usar para identificar un conjunto de tipos sin necesidad de ningún comportamiento específico. Estas interfaces no tienen miembros y sirven como una manera de marcar o etiquetar tipos con fines de categorización.
Defina una interfaz vacía con la interface end sintaxis :
// Define an empty interface (also known as a marker interface)
type IMarker =
interface end
// Implement the empty interface in a record type
type MyRecord =
{ Name: string }
interface IMarker
// Implement the empty interface in a class type
type MyClass(value: int) =
member _.Value = value
interface IMarker
En el ejemplo anterior, IMarker se define como una interfaz vacía. Tanto como MyRecordMyClass implementen esta interfaz sin necesidad de proporcionar ninguna implementación de método, ya que la interfaz no tiene miembros. Esto le permite usar el tipo de interfaz para identificar y trabajar con estos tipos de forma común.
Métodos de interfaz de llamada
Solo se puede llamar a métodos de interfaz a través de la interfaz, no a través de ningún objeto del tipo que implemente la interfaz. Por lo tanto, es posible que tenga que realizar la difusión al tipo de interfaz mediante el :> operador o el upcast operador para llamar a estos métodos.
Para llamar al método de interfaz cuando tenga un objeto de tipo SomeClass, debe convertir el objeto al tipo de interfaz, como se muestra en el código siguiente.
let x1 = new SomeClass1(1, 2.0)
(x1 :> IPrintable).Print()
Una alternativa consiste en declarar un método en el objeto que actualiza y llama al método de interfaz, como en el ejemplo siguiente.
type SomeClass2(x: int, y: float) =
member this.Print() = (this :> IPrintable).Print()
interface IPrintable with
member this.Print() = printfn "%d %f" x y
let x2 = new SomeClass2(1, 2.0)
x2.Print()
Implementación de interfaces mediante expresiones de objeto
Las expresiones de objeto proporcionan una manera corta de implementar una interfaz. Son útiles cuando no es necesario crear un tipo con nombre y solo desea un objeto que admita los métodos de interfaz, sin ningún método adicional. En el código siguiente se muestra una expresión de objeto.
let makePrintable (x: int, y: float) =
{ new IPrintable with
member this.Print() = printfn "%d %f" x y }
let x3 = makePrintable (1, 2.0)
x3.Print()
Herencia de interfaz
Las interfaces pueden heredar de una o varias interfaces base.
type Interface1 =
abstract member Method1: int -> int
type Interface2 =
abstract member Method2: int -> int
type Interface3 =
inherit Interface1
inherit Interface2
abstract member Method3: int -> int
type MyClass() =
interface Interface3 with
member this.Method1(n) = 2 * n
member this.Method2(n) = n + 100
member this.Method3(n) = n / 10
Implementación de interfaces con implementaciones predeterminadas
C# admite la definición de interfaces con implementaciones predeterminadas, de la siguiente manera:
using System;
namespace CSharp
{
public interface MyDim
{
public int Z => 0;
}
}
Estos son consumibles directamente desde F#:
open CSharp
// You can implement the interface via a class
type MyType() =
member _.M() = ()
interface MyDim
let md = MyType() :> MyDim
printfn $"DIM from C#: %d{md.Z}"
// You can also implement it via an object expression
let md' = { new MyDim }
printfn $"DIM from C# but via Object Expression: %d{md'.Z}"
Puede invalidar una implementación predeterminada con override, como invalidar cualquier miembro virtual.
Los miembros de una interfaz que no tienen una implementación predeterminada deben seguir implementarse explícitamente.
Implementación de la misma interfaz en instancias genéricas diferentes
F# admite la implementación de la misma interfaz en instancias genéricas diferentes, como por ejemplo:
type IA<'T> =
abstract member Get : unit -> 'T
type MyClass() =
interface IA<int> with
member x.Get() = 1
interface IA<string> with
member x.Get() = "hello"
let mc = MyClass()
let iaInt = mc :> IA<int>
let iaString = mc :> IA<string>
iaInt.Get() // 1
iaString.Get() // "hello"