Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
As interfaces especificam conjuntos de membros relacionados que outras classes implementam.
Sintaxe
// 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
Observações
As declarações de interface se assemelham a declarações de classe, exceto que nenhum membro é implementado. Em vez disso, todos os membros são abstratos, conforme indicado pela palavra-chave abstract. Você não fornece um corpo de método para métodos abstratos. O F# não pode definir uma implementação de método padrão em uma interface, mas é compatível com implementações padrão definidas por C#. Implementações padrão usando a default palavra-chave só têm suporte ao herdar de uma classe base que não seja de interface.
A acessibilidade padrão para interfaces é public.
Opcionalmente, você pode dar um nome a cada parâmetro de método usando a sintaxe F# normal:
type ISprintable =
abstract member Print: format: string -> unit
No exemplo acima ISprintable , o Print método tem um único parâmetro do tipo string com o nome format.
Há duas maneiras de implementar interfaces: usando expressões de objeto e usando tipos. Em ambos os casos, a expressão de tipo ou objeto fornece corpos de método para métodos abstratos da interface. As implementações são específicas para cada tipo que implementa a interface. Portanto, os métodos de interface em diferentes tipos podem ser diferentes uns dos outros.
As palavras-chave interface e end, que marcam o início e o final da definição, são opcionais quando você usa sintaxe leve. Se você não usar essas palavras-chave, o compilador tentará inferir se o tipo é uma classe ou uma interface analisando os constructos que você usa. Se você definir um membro ou usar outra sintaxe de classe, o tipo será interpretado como uma classe.
O estilo de codificação do .NET é iniciar todas as interfaces com um capital I.
Você pode especificar vários parâmetros de duas maneiras: estilo F#e . Estilo NET. Ambos serão compilados da mesma maneira para os consumidores do .NET, mas o estilo F#forçará os chamadores F# a usar o aplicativo de parâmetro estilo F#e . O estilo NET forçará os chamadores F# a usar o aplicativo de argumento tupled.
type INumericFSharp =
abstract Add: x: int -> y: int -> int
type INumericDotNet =
abstract Add: x: int * y: int -> int
Implementando interfaces usando tipos de classe
Você pode implementar uma ou mais interfaces em um tipo de classe usando a interface palavra-chave, o nome da interface e a with palavra-chave, seguidas pelas definições de membro da interface, conforme mostrado no código a seguir.
type IPrintable =
abstract member Print: unit -> unit
type SomeClass1(x: int, y: float) =
interface IPrintable with
member this.Print() = printfn "%d %f" x y
As implementações de interface são herdadas, portanto, todas as classes derivadas não precisam reimplementá-las.
Definir interfaces vazias ou de marcador
Interfaces vazias, também conhecidas como interfaces de marcador, podem ser usadas para identificar um conjunto de tipos sem exigir nenhum comportamento específico. Essas interfaces não têm membros e servem como uma forma de marcar ou marcar tipos para fins de categorização.
Você define uma interface vazia usando a interface end sintaxe:
// 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
No exemplo acima, IMarker é definido como uma interface vazia.
MyClass E MyRecord implemente essa interface sem a necessidade de fornecer implementações de método, pois a interface não tem membros. Isso permite que você use o tipo de interface para identificar e trabalhar com esses tipos de maneira comum.
Métodos de interface de chamada
Os métodos de interface só podem ser chamados por meio da interface, não por meio de qualquer objeto do tipo que implementa a interface. Portanto, talvez seja necessário fazer upcast para o tipo de interface usando o :> operador ou o upcast operador para chamar esses métodos.
Para chamar o método de interface quando você tiver um objeto do tipo SomeClass, você deve atualizar o objeto para o tipo de interface, conforme mostrado no código a seguir.
let x1 = new SomeClass1(1, 2.0)
(x1 :> IPrintable).Print()
Uma alternativa é declarar um método no objeto que ativa e chama o método de interface, como no exemplo a seguir.
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()
Implementando interfaces usando expressões de objeto
As expressões de objeto fornecem uma maneira curta de implementar uma interface. Elas são úteis quando você não precisa criar um tipo nomeado e você só quer um objeto que dê suporte aos métodos de interface, sem nenhum método adicional. Uma expressão de objeto é ilustrada no código a seguir.
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()
Herança de interface
As interfaces podem herdar de uma ou mais 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
Implementando interfaces com implementações padrão
O C# dá suporte à definição de interfaces com implementações padrão, assim como:
using System;
namespace CSharp
{
public interface MyDim
{
public int Z => 0;
}
}
Eles são diretamente consumíveis de 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}"
Você pode substituir uma implementação padrão com override, como substituir qualquer membro virtual.
Todos os membros em uma interface que não têm uma implementação padrão ainda devem ser implementados explicitamente.
Implementando a mesma interface em instâncias genéricas diferentes
O F# dá suporte à implementação da mesma interface em instâncias genéricas diferentes como esta:
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"