Typtillägg
Typtillägg (kallas även förökningar) är en uppsättning funktioner som gör att du kan lägga till nya medlemmar i en tidigare definierad objekttyp. De tre funktionerna är:
- Tillägg av inbyggd typ
- Valfria typtillägg
- Tilläggsmetoder
Var och en kan användas i olika scenarier och har olika kompromisser.
Syntax
// Intrinsic and optional extensions
type typename with
member self-identifier.member-name =
body
...
// Extension methods
open System.Runtime.CompilerServices
[<Extension>]
type Extensions() =
[<Extension>]
static member extension-name (ty: typename, [args]) =
body
...
Tillägg av inbyggd typ
Ett tillägg av inbyggd typ är ett typtillägg som utökar en användardefinierad typ.
Tillägg av inbyggd typ måste definieras i samma fil och i samma namnområde eller modul som den typ som de utökar. Alla andra definitioner resulterar i att de är valfria typtillägg.
Tillägg av inbyggd typ är ibland ett renare sätt att skilja funktioner från typdeklarationen. I följande exempel visas hur du definierar ett tillägg av inbyggd typ:
namespace Example
type Variant =
| Num of int
| Str of string
module Variant =
let print v =
match v with
| Num n -> printf "Num %d" n
| Str s -> printf "Str %s" s
// Add a member to Variant as an extension
type Variant with
member x.Print() = Variant.print x
Med hjälp av ett typtillägg kan du separera var och en av följande:
- Deklarationen av en
Variant
typ - Funktioner för att skriva ut
Variant
klassen beroende på dess "form" - Ett sätt att komma åt utskriftsfunktionen med objektformatet
.
-notation
Det här är ett alternativ till att definiera allt som medlem på Variant
. Även om det inte är en i sig bättre metod kan det vara en renare representation av funktioner i vissa situationer.
Tillägg av inbyggd typ kompileras som medlemmar av den typ som de utökar och visas på typen när typen granskas med reflektion.
Valfria typtillägg
Ett tillägg av valfri typ är ett tillägg som visas utanför den ursprungliga modulen, namnområdet eller sammansättningen av den typ som utökas.
Valfria typtillägg är användbara för att utöka en typ som du inte har definierat själv. Till exempel:
module Extensions
type IEnumerable<'T> with
/// Repeat each element of the sequence n times
member xs.RepeatElements(n: int) =
seq {
for x in xs do
for _ in 1 .. n -> x
}
Nu kan du komma åt RepeatElements
den som om den är medlem IEnumerable<T> i så länge modulen Extensions
öppnas i det omfång som du arbetar i.
Valfria tillägg visas inte på den utökade typen när de granskas av reflektion. Valfria tillägg måste finnas i moduler och de finns bara i omfånget när modulen som innehåller tillägget är öppen eller på annat sätt finns i omfånget.
Valfria tilläggsmedlemmar kompileras till statiska medlemmar för vilka objektinstansen implicit skickas som den första parametern. De fungerar dock som om de är instansmedlemmar eller statiska medlemmar beroende på hur de deklareras.
Valfria tilläggsmedlemmar är inte heller synliga för C# eller Visual Basic-användare. De kan bara användas i annan F#-kod.
Allmän begränsning av inbyggda och valfria typtillägg
Det går att deklarera ett typtillägg för en allmän typ där typvariabeln är begränsad. Kravet är att villkoret för tilläggsdeklarationen matchar villkoret för den deklarerade typen.
Men även om begränsningar matchas mellan en deklarerad typ och ett typtillägg är det möjligt att en begränsning härleds av brödtexten för en utökad medlem som ställer ett annat krav på typparametern än den deklarerade typen. Till exempel:
open System.Collections.Generic
// NOT POSSIBLE AND FAILS TO COMPILE!
//
// The member 'Sum' has a different requirement on 'T than the type IEnumerable<'T>
type IEnumerable<'T> with
member this.Sum() = Seq.sum this
Det finns inget sätt att få den här koden att fungera med ett valfritt typtillägg:
- Som det är
Sum
har medlemmen en annan begränsning för'T
(static member get_Zero
ochstatic member (+)
) än vad typtillägget definierar. - Ändra typtillägget så att det har samma villkor som
Sum
inte längre matchar den definierade begränsningen förIEnumerable<'T>
. - Om du ändrar
member this.Sum
tillmember inline this.Sum
får du ett fel om att typbegränsningarna är matchningsfel.
Vad som önskas är statiska metoder som "flyter i rymden" och kan visas som om de utökar en typ. Det är här tilläggsmetoderna blir nödvändiga.
Tilläggsmetoder
Slutligen kan tilläggsmetoder (kallas ibland "C#-formattilläggsmedlemmar") deklareras i F# som en statisk medlemsmetod i en klass.
Tilläggsmetoder är användbara när du vill definiera tillägg för en allmän typ som begränsar typvariabeln. Till exempel:
namespace Extensions
open System.Collections.Generic
open System.Runtime.CompilerServices
[<Extension>]
type IEnumerableExtensions =
[<Extension>]
static member inline Sum(xs: IEnumerable<'T>) = Seq.sum xs
När den här koden används visas den som om Sum
den har definierats på IEnumerable<T>, så länge som Extensions
har öppnats eller finns i omfånget.
För att tillägget ska vara tillgängligt för VB.NET kod krävs ett extra ExtensionAttribute
tillägg på sammansättningsnivå:
module AssemblyInfo
open System.Runtime.CompilerServices
[<assembly:Extension>]
do ()
Andra kommentarer
Typtillägg har också följande attribut:
- Alla typer som kan nås kan utökas.
- Inbyggda och valfria typtillägg kan definiera alla medlemstyper, inte bara metoder. Så tilläggsegenskaper är också möjliga, till exempel.
- Token
self-identifier
i syntaxen representerar den instans av typen som anropas, precis som vanliga medlemmar. - Utökade medlemmar kan vara statiska medlemmar eller instansmedlemmar.
- Typvariabler för ett typtillägg måste matcha begränsningarna för den deklarerade typen.
Följande begränsningar finns också för typtillägg:
- Typtillägg stöder inte virtuella eller abstrakta metoder.
- Typtillägg stöder inte åsidosättningsmetoder som förhöjda funktioner.
- Typtillägg stöder inte statiskt lösta typparametrar.
- Valfria typtillägg stöder inte konstruktorer som förhöjda objekt.
- Det går inte att definiera typtillägg för typförkortningar.
- Typtillägg är inte giltiga för
byref<'T>
(även om de kan deklareras). - Typtillägg är inte giltiga för attribut (även om de kan deklareras).
- Du kan definiera tillägg som överbelastar andra metoder med samma namn, men F#-kompilatorn föredrar icke-tilläggsmetoder om det finns ett tvetydigt anrop.
Om det finns flera inbyggda typtillägg för en typ måste alla medlemmar vara unika. För valfria typtillägg kan medlemmar i olika typtillägg till samma typ ha samma namn. Tvetydighetsfel uppstår endast om klientkoden öppnar två olika omfång som definierar samma medlemsnamn.