Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
F# 10 bietet Ihnen verschiedene Verbesserungen an der F#-Sprache, der FSharp.Core-Bibliothek und der Tools. Diese Version ist eine Optimierungsversion, die sich auf Klarheit, Konsistenz und Leistung konzentriert und durch kleine, aber bedeutende Verbesserungen Ihren alltäglichen Code lesbarer und robuster macht. F# 10 wird mit .NET 10 und Visual Studio 2026 ausgeliefert.
Sie können das neueste .NET SDK von der .NET-Downloadseite herunterladen.
Get started
F# 10 ist in allen .NET Core-Verteilungen und Visual Studio-Tools verfügbar. Weitere Informationen finden Sie unter "Erste Schritte mit F#".
Unterdrückung von Bereichswarnungen
Sie können warnungen jetzt in bestimmten Abschnitten Ihres Codes mithilfe der neuen #warnon Direktive unterdrücken.
Dies passt zu der vorhandenen #nowarn Direktive, um Ihnen eine genaue Kontrolle darüber zu geben, welche Warnungen wo gelten.
Wenn Sie zuvor #nowarn verwendet haben, würde es eine Warnung für den Rest der Datei deaktivieren, wodurch legitime Probleme an anderen Stellen unterdrückt werden könnten.
Sehen wir uns ein motivierendes Beispiel an:
// We know f is never called with None.
let f (Some a) = // creates warning 25, which we want to suppress
// 2000 loc, where the incomplete match warning is beneficial
Wenn Sie oberhalb der Funktionsdefinition hinzufügen #nowarn 25 , wird FS0025 für den gesamten Rest der Datei deaktiviert.
Mit F# 10 können Sie nun den genauen Abschnitt markieren, in dem die Warnung unterdrückt werden soll:
#nowarn 25
let f (Some x) = // FS0025 suppressed
#warnon 25
// FS0025 enabled again
Wenn eine Warnung dagegen global deaktiviert ist (z. B. über ein Compilerflagge), können Sie sie lokal mit #warnonaktivieren.
Diese Direktive gilt bis zu einem übereinstimmenden #nowarn oder bis zum Ende der Datei.
Wichtige Kompatibilitätshinweise:
Dieses Feature enthält mehrere Änderungen, die die Konsistenz von #nowarn/#warnon Direktiven verbessern.
Dies sind bahnbrechende Änderungen:
- Der Compiler lässt keine mehrline- und leeren Warndirektiven mehr zu.
- Der Compiler erlaubt keine Leerzeichen mehr zwischen
#undnowarn. - Sie können keine dreifache Zeichenfolge, interpolierte oder verbatim Zeichenfolgen für Warnungsnummern verwenden.
Das Skriptverhalten hat sich ebenfalls geändert.
Wenn Sie zuvor eine #nowarn Direktive an einer beliebigen Stelle in einem Skript hinzugefügt haben, wird sie auf die gesamte Kompilierung angewendet.
Das Verhalten in Skripts stimmt nun mit dem Verhalten in .fs-Dateien überein und gilt nur bis zum Ende der Datei oder einem entsprechenden #warnon.
Dieses Feature implementiert RFC FS-1146.
Zugriffsmodifizierer für automatische Eigenschaftenaccessoren
Ein gängiges Muster in der objektorientierten Programmierung besteht darin, öffentlich lesbaren, aber privat änderbaren Zustand zu erstellen. Vor F# 10 benötigten Sie eine explizite Eigenschaftssyntax mit Speicherfeldern (versteckte Felder, die die tatsächlichen Eigenschaftswerte speichern), um dies zu erreichen, was zu wiederholtem Code führte:
type Ledger() =
[<DefaultValue>] val mutable private _Balance: decimal
member this.Balance with public get() = this._Balance and private set v = this._Balance <- v
Mit F# 10 können Sie jetzt verschiedene Zugriffsmodifizierer auf einzelne Eigenschaftsaccessoren anwenden. Auf diese Weise können Sie unterschiedliche Zugriffsebenen für den Getter und Setter einer Eigenschaft angeben, wodurch das Muster wesentlich einfacher wird:
type Ledger() =
member val Balance = 0m with public get, private set
Sie können einen Zugriffsmodifizierer entweder vor dem Eigenschaftennamen (anwenden auf beide Accessoren) oder vor einzelnen Accessoren, aber nicht gleichzeitig platzieren.
Beachten Sie, dass dieses Feature nicht auf Signaturdateien (.fsi) erweitert wird.
Die richtige Signatur für das Ledger obige Beispiel lautet:
type Ledger() =
member Balance : decimal
member private Balance : decimal with set
Dieses Feature implementiert RFC FS-1141.
Optionale Parameter "ValueOption"
Sie können jetzt eine strukturbasierte ValueOption<'T> Darstellung für optionale Parameter verwenden.
Wenn Sie das [<Struct>] Attribut auf einen optionalen Parameter anwenden, verwendet ValueOption<'T> der Compiler anstelle des referenzbasierten option Typs.
Dadurch werden Heap-Zuordnungen (Speicher, der für den verwalteten Heap zugeordnet ist, der Garbage Collection erfordert) für den Optionswrapper vermieden, der im leistungskritischen Code von Vorteil ist.
Zuvor hat F# immer den heap zugewiesenen option Typ für optionale Parameter verwendet, auch wenn der Parameter nicht vorhanden war:
// Prior to F# 10: always uses reference option
type X() =
static member M(?x : string) =
match x with
| Some v -> printfn "Some %s" v
| None -> printfn "None"
In F# 10 können Sie das [<Struct>]-Attribut verwenden, um die strukturgestützte ValueOption Struktur zu nutzen:
type X() =
static member M([<Struct>] ?x : string) =
match x with
| ValueSome v -> printfn "ValueSome %s" v
| ValueNone -> printfn "ValueNone"
Dadurch werden Heap-Allokationen vermieden, wenn das Argument nicht vorhanden ist, was bei leistungskritischem Code von Vorteil ist.
Wählen Sie diese strukturbasierte Option für kleine Werte oder häufig konstruierte Typen aus, bei denen zuordnungsdruck wichtig ist.
Verwenden Sie die standardreferenzbasierte option, wenn Sie auf vorhandene Hilfsprogramme zur Mustererkennung angewiesen sind, eine Referenzsemantik benötigen oder wenn der Leistungsunterschied vernachlässigbar ist.
Dieses Feature stärkt die Parität mit anderen F#-Sprachkonstrukten, die bereits ValueOption unterstützen.
Unterstützung für Endrekursion in Berechnungsausdrücken
F# 10 fügt Tail-Call-Optimierungen für Berechnungsausdrücke hinzu. Berechnungsausdruck-Generatoren können sich jetzt für diese Optimierungen entscheiden, indem spezielle Methoden implementiert werden.
Wenn der Compiler Berechnungsausdrücke in regulären F#-Code übersetzt (ein Prozess namens Desugaring), erkennt er, wann ein Ausdruck wie return!, yield!oder do! in einer Tailposition angezeigt wird.
Wenn Ihr Generator die folgenden Methoden bereitstellt, leitet der Compiler diese Aufrufe an optimierte Einstiegspunkte weiter:
-
ReturnFromFinal- aufgerufen für einen Anhängerreturn!(fällt aufReturnFromzurück, wenn nicht vorhanden) -
YieldFromFinal- aufgerufen für einen Schwanzyield!(fällt zurück,YieldFromwenn nicht vorhanden) - Für ein Terminal
do!bevorzugt der Compiler zunächstReturnFromFinal, dannYieldFromFinal, bevor er auf den normalenBind-Pfad zurückfällt.
Diese *Final Member sind optional und nur vorhanden, um die Optimierung zu ermöglichen.
Generatoren, die diese Member nicht bereitstellen, behalten ihre vorhandene Semantik unverändert.
Beispiel:
coroutine {
yield! subRoutine() // tail position -> YieldFromFinal if available
}
Allerdings in einer Nicht-Tail-Position:
coroutine {
try
yield! subRoutine() // not tail -> normal YieldFrom
finally ()
}
Wichtiger Kompatibilitätshinweis:
Diese Änderung kann abgebrochen werden, wenn ein Berechnungsausdruck-Generator bereits Member mit diesen Namen definiert.
In den meisten Fällen funktionieren vorhandene Generatoren weiterhin ohne Änderung, wenn sie mit F# 10 kompiliert wurden.
Ältere Compiler ignorieren die neuen *Final Methoden, sodass Generatoren, die mit früheren Compilerversionen kompatibel bleiben müssen, nicht davon ausgehen, dass der Compiler diese Methoden aufruft.
Dieses Feature implementiert RFC FS-1330.
Eingegebene Bindungen in Berechnungsausdrücken ohne Klammern
F# 10 entfernt die Anforderung für Klammern beim Hinzufügen von Typanmerkungen zu Berechnungsausdrucksbindungen.
Sie können jetzt Typanmerkungen zu let!, use!und and! Bindungen mit der gleichen Syntax wie normale let Bindungen hinzufügen.
Zuvor mussten Sie Klammern für Typanmerkungen verwenden:
async {
let! (a: int) = fetchA()
and! (b: int) = fetchB()
use! (d: MyDisposable) = acquireAsync()
return a + b
}
In F# 10 können Sie Typanmerkungen ohne Klammern schreiben:
async {
let! a: int = fetchA()
and! b: int = fetchB()
use! d: MyDisposable = acquireAsync()
return a + b
}
Zulassen _ in use! Bindungen
Sie können jetzt das Verwerfenmuster (_) in use! Bindungen innerhalb von Berechnungsausdrücken verwenden.
Dadurch wird das Verhalten von use! mit den regulären use-Bindungen abgestimmt.
Zuvor hat der Compiler das Verwerfungsmuster in use! Bindungen abgelehnt, weshalb Sie gezwungen waren, Wegwerf-Identifiern zu erstellen.
counterDisposable {
use! _ignored = new Disposable()
// logic
}
In F# 10 können Sie das Verwerfenmuster direkt verwenden:
counterDisposable {
use! _ = new Disposable()
// logic
}
Dadurch wird die Absicht klargestellt, wenn asynchrone Ressourcen gebunden werden, deren Werte nur für die Lebensdauerverwaltung erforderlich sind.
Ablehnen von pseudogeschachtelten Modulen in Typen
Der Compiler löst jetzt einen Fehler aus, wenn Sie eine module-Deklaration auf derselben Strukturebene innerhalb einer Typdefinition platzieren.
Dadurch wird die Strukturelle Validierung verschärft, um irreführende Modulplatzierung innerhalb von Typen abzulehnen.
Zuvor akzeptierte der Compiler module Deklarationen, die innerhalb von Typdefinitionen eingerückt waren. Tatsächlich wurden diese Module jedoch als gleichgeordnete Module neben dem Typ erstellt, anstatt sie darin zu verschachteln.
type U =
| A
| B
module M = // Silently created a sibling module, not nested
let f () = ()
Mit F# 10 löst dieses Muster fehler FS0058 aus, wodurch Sie gezwungen werden, Ihre Absicht mit der richtigen Modulplatzierung zu klären:
type U =
| A
| B
module M =
let f () = ()
Veraltungswarnung für weggelassenes seq
Der Compiler warnt Sie jetzt vor reinen Sequenzausdrücken, die den seq Generator weglassen.
Wenn Sie Klammern für den offenen Bereich wie { 1..10 } verwenden, wird eine Warnung angezeigt, in der Sie aufgefordert werden, die explizite seq { ... } Form zu verwenden.
In der Vergangenheit erlaubte F# eine Spezialfall-"Sequenzkomprehension-Lite"-Syntax, in der Sie das seq Schlüsselwort weglassen könnten.
{ 1..10 } |> List.ofSeq // implicit sequence, warning FS3873 in F# 10
In F# 10 warnt der Compiler über dieses Muster und ermutigt die explizite Form:
seq { 1..10 } |> List.ofSeq
Dies ist derzeit eine Warnung und kein Fehler, sodass Sie Zeit haben, Ihre Codebasis zu aktualisieren.
Wenn Sie diese Warnung unterdrücken möchten, verwenden Sie die NoWarn-Eigenschaft in Ihrer Projektdatei oder die lokale #nowarn-Direktive und geben Sie die Warnnummer 3873 an.
Das explizite seq Formular verbessert die Codeklarheit und Konsistenz mit anderen Berechnungsausdrücken.
Bei zukünftigen Versionen von F# kann dies zu einem Fehler führen. Daher wird empfohlen, die explizite Syntax zu übernehmen, wenn Sie Ihren Code aktualisieren.
Dieses Feature implementiert RFC FS-1033.
Attributzielerzwingung
F# 10 erzwingt die Attributzielüberprüfung für alle Sprachkonstrukte.
Der Compiler überprüft jetzt, ob Attribute nur auf ihre beabsichtigten Ziele angewendet werden, indem er let-gebundene Werte, Funktionen, Unionsfälle, implizite Konstruktoren, Strukturen und Klassen überprüft AttributeTargets.
Zuvor erlaubte der Compiler Ihnen ohne Hinweis, Attribute auf inkompatible Bestimmungen falsch anzuwenden.
Dies verursachte versteckte Fehler, wie zum Beispiel Testattribute, die ignoriert wurden, wenn Sie vergessen haben, eine Funktion zu erstellen:()
[<Fact>]
let ``this is not a function`` = // Silently ignored in F# 9, not a test!
Assert.True(false)
In F# 10 erzwingt der Compiler Attributziele und löst eine Warnung aus, wenn Attribute falsch angewendet werden:
[<Fact>]
//^^^^ - warning FS0842: This attribute cannot be applied to property, field, return value. Valid targets are: method
let ``this is not a function`` =
Assert.True(false)
Wichtiger Kompatibilitätshinweis:
Dies ist eine wichtige Änderung, die möglicherweise zuvor unbeaufsichtigte Probleme in Ihrer Codebasis aufdecken kann. Die frühen Fehler verhindern Testerkennungsprobleme und stellen sicher, dass Attribute wie Analyzer und Dekorateure wie beabsichtigt wirksam werden.
Unterstützung für and! bei Aufgabenausdrücken
Sie können jetzt mehrere Aufgaben gleichzeitig mit and! in Aufgabenausdrücken erwarten.
Die Verwendung task ist eine beliebte Möglichkeit, mit asynchronen Workflows in F# zu arbeiten, insbesondere, wenn Sie Interoperabilität mit C# benötigen.
Bisher gab es jedoch keine präzise Möglichkeit, mehrere Aufgaben gleichzeitig in einem Berechnungsausdruck abzuwarten.
Vielleicht haben Sie mit Code begonnen, der sequenziell auf Berechnungen wartete:
// Awaiting sequentially
task {
let! a = fetchA()
let! b = fetchB()
return combineAB a b
}
Wenn Sie sie dann so ändern möchten, dass sie gleichzeitig erwartet werden, würden Sie in der Regel Folgendes verwenden Task.WhenAll:
// Use explicit Task combinator to await concurrently
task {
let ta = fetchA()
let tb = fetchB()
let! results = Task.WhenAll([| ta; tb |])
return combineAB ta.Result tb.Result
}
In F# 10 können Sie and! für einen idiomatischeren Ansatz verwenden.
task {
let! a = fetchA()
and! b = fetchB()
return combineAB a b
}
Dies kombiniert die Semantik der gleichzeitigen Version mit der Einfachheit der sequenziellen Version.
Dieses Feature implementiert F#-Sprachvorschlag #1363 und wird als Ergänzung zur FSharp.Core Bibliothek implementiert.
Die meisten Projekte erhalten die neueste Version FSharp.Core automatisch vom Compiler, es sei denn, sie legen eine Version explizit fest.
In diesem Fall müssen Sie es aktualisieren, um dieses Feature zu verwenden.
Bessere Kürzung standardmäßig
F# 10 beseitigt einen langjährigen Reibungspunkt durch die Reduzierung von F#-Assemblys.
Das Kürzen ist der Vorgang zum Entfernen nicht verwendeter Code aus der veröffentlichten Anwendung, um die Größe zu verringern.
Sie müssen eine ILLink.Substitutions.xml Datei nicht mehr manuell verwalten, um große F#-Metadatenressourcen-Blobs zu entfernen (Signatur- und Optimierungsdaten, die der Compiler verwendet, aber Ihre Anwendung benötigt nicht zur Laufzeit).
Wenn Sie mit aktivierter Kürzung veröffentlichen (PublishTrimmed=true), generiert der F#-Build jetzt automatisch eine eingebettete Ersetzungsdatei, die auf diese Tooling-only F#-Ressourcen ausgerichtet ist.
Zuvor mussten Sie diese Datei manuell verwalten, um die Metadaten zu entfernen. Diese zusätzliche Wartungslast war leicht zu vergessen.
Das Ergebnis ist standardmäßig eine kleinere Ausgabe, weniger sich wiederholender Code für die Wartung und ein weniger Wartungsrisiko.
Wenn Sie die vollständige manuelle Kontrolle benötigen, können Sie weiterhin Ihre eigene Ersetzungsdatei hinzufügen.
Sie können die automatische Generierung mit der <DisableILLinkSubstitutions>false</DisableILLinkSubstitutions> Eigenschaft deaktivieren.
Parallele Kompilierung in der Vorschau
Ein spannendes Update für F#-Benutzer, die Kompilierungszeiten reduzieren möchten: Die parallelen Kompilierungsfeatures sind stabil.
Ab .NET 10 werden drei Features: graphbasierte Typüberprüfung, parallele Generierung von IL-Code und parallele Optimierung unter der ParallelCompilation Projekteigenschaft gruppiert.
F# 10 aktiviert diese Einstellung standardmäßig für Projekte mit LangVersion=Preview.
Wir planen die Aktivierung für alle Projekte in .NET 11.
Versuchen Sie es unbedingt, und überprüfen Sie, ob die Kompilierung beschleunigt wird. So aktivieren Sie die parallele Kompilierung in F# 10:
<PropertyGroup>
<ParallelCompilation>true</ParallelCompilation>
<Deterministic>false</Deterministic> <!-- Note: deterministic builds don't get the benefits of parallel compilation -->
</PropertyGroup>
Wenn Sie sich abmelden möchten, während Sie weiterhin andere Vorschaufeatures nutzen möchten, legen Sie ParallelCompilation "false" fest:
<PropertyGroup>
<LangVersion>Preview</LangVersion>
<ParallelCompilation>false</ParallelCompilation>
</PropertyGroup>
Die parallele Kompilierung kann die Kompilierungszeit für Projekte mit mehreren Dateien und Abhängigkeiten erheblich reduzieren.
Typ des Untervermutungscaches
Der Compiler speichert jetzt Typbeziehungsprüfungen zwischen, um die Typausleitung zu beschleunigen und die IDE-Leistung zu verbessern, insbesondere beim Arbeiten mit komplexen Typhierarchien. Durch speichern und wiederverwenden von Ergebnissen aus früheren Untervermutungsprüfungen vermeidet der Compiler redundante Berechnungen, die zuvor die Kompilierung und IntelliSense verlangsamt haben.
Verwalten des Caches:
In den meisten Fällen verbessert der Typuntervermutungscache die Leistung ohne Konfiguration. Wenn Sie jedoch einen erhöhten Speicherbedarf oder eine erhöhte CPU-Auslastung (aufgrund von Cachewartungsmitarbeitern) feststellen, können Sie das Cacheverhalten anpassen:
- Wenn Sie den Cache vollständig deaktivieren möchten, legen Sie fest, dass
<LangVersion>9</LangVersion>in Ihrer Projektdatei auf das frühere Verhalten von F# 9 zurückgreift. - Legen Sie die
FSharp_CacheEvictionImmediate=1Umgebungsvariable fest, um die asynchrone Cache-Eviction (was den Threaddruck erhöht) zu deaktivieren und stattdessen synchrone Eviction zu verwenden.