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.
Um Felder freizugeben, ohne unterschiedliche Modelltypen zusammenzuführen, verwenden Sie Datensatzbreiten, die ab F# 11 verfügbar sind.
Dient ...Type zum Beitragen von Felddeklarationen zu einem neuen benannten Datensatz oder ...expression zum Beitragen von Feldwerten zu einem benannten oder anonymen Datensatz. Deklarationswiederverwendung und Wertzuordnung sind unabhängige Auswahlmöglichkeiten.
Verfassen von Datensatztypen
Um Verbindungsfelder über Konfigurationstypen hinweg zu teilen, verteilen Sie sich Endpoint in eine neue Datensatzdeklaration:
type Endpoint = { Host: string; Port: int }
type ClientOptions =
{ ...Endpoint
TimeoutSeconds: int }
ClientOptions hat Host, Port, und TimeoutSeconds. Es handelt sich um einen eindeutigen Nominaltyp, nicht um einen Endpoint Untertyp.
Mehrere Quellen und explizite Deklarationen können in derselben Typdefinition angezeigt werden:
type Logging = { LogLevel: string }
type LoggedClientOptions = { ...ClientOptions; ...Logging }
Nur Datensatzfelder sind teil. Methoden, Eigenschaften, die keine Datensatzfelder sind, und statische Member werden nicht kopiert. Eine Quelle kann ein benannter Datensatz oder ein anonymer Datensatztyp sein, einschließlich einer Abkürzung für einen anonymen Datensatz. Das Ziel eines Typs "Spread" muss ein benannter Datensatztyp sein.
Verfassen von Datensatzwerten
Kopieren Sie den Endpunkt in Clientoptionen, und verwenden Sie dann einen anonymen Datensatz, um den Host zu ersetzen:
let local = { Host = "localhost"; Port = 5432 }
let options: ClientOptions = { ...local; TimeoutSeconds = 30 }
let remote = {| ...options; Host = "db.example.com" |}
printn $"{remote.Host}:{remote.Port}, timeout {remote.TimeoutSeconds}s"
// db.example.com:5432, timeout 30s
Ausdrucksausdrücke akzeptieren benannte oder anonyme Datensatzquellen und Ziele, einschließlich Strukturdatensätze. Jedes Zielfeld muss einen Wert erhalten. Eine explizite Zielanmerkung ist nützlich, wenn mehrere benannte Datensatztypen Bezeichnungen freigeben.
Stärken des Feldtyps
Eine spätere Felddeklaration kann den Typ eines Spread-Felds ersetzen. Stellen Sie beispielsweise einen analysierten Bezeichner mit type CustomerId = CustomerId of System.Guid, und unterscheiden Sie dann einen importierten Datensatz von einem mit diesem Bezeichner:
type ImportedCustomer = { Name: string; Id: string }
type IdentifiedCustomer = { ...ImportedCustomer; Id: CustomerId }
let identify (source: ImportedCustomer) =
match Guid.TryParse source.Id with
| true, id -> Ok ({ ...source; Id = CustomerId id }: IdentifiedCustomer)
| false, _ -> Error "Invalid customer identifier."
Guid.TryParse überprüft den Text; die Ansicht kopiert nur Felder.
CustomerId unterscheidet Bezeichner von anderen GUIDs, ohne weitere Regeln zu erzwingen.
Kombinieren unabhängiger Modelle
Verfassen Sie Deklarationen aus einem kuratierten Nominaldatensatz und einem anonymen Datensatztyp, und fügen Sie dann Werte aus unabhängigen Quellen zusammen:
type PublicProductFields = { Name: string; UnitPrice: decimal }
type ProductRow = { ...PublicProductFields; InternalCost: decimal }
type StockCounts = {| InStock: int; Reserved: int |}
type ProductCard =
{ ...PublicProductFields
...StockCounts
CanOrder: bool }
let product: ProductRow =
{ Name = "Notebook"; UnitPrice = 12.50m; InternalCost = 4m }
let stock: StockCounts = {| InStock = 8; Reserved = 2 |}
let card: ProductCard =
{ ...product; ...stock; CanOrder = stock.InStock > stock.Reserved }
let viewState = {| ...card; Selected = false |}
let selected = {| ...viewState; Selected = true |}
Benannte und anonyme Quellen liefern ProductCard; die Karte liefert dann den Status der anonymen Ansicht.
CanOrder wird einmal berechnet, nicht neu berechnet, wenn eine spätere Konstruktion die Anzahl ändert.
Project in ein bekanntes Ziel
Ein Zieltyp wählt die zu behaltenden Felder aus. Mehrere Quellen können Ersatz liefern:
let endpoint: Endpoint = { ...options }
let overrides = {| Host = "db.example.com"; Port = 5433 |}
let production: ClientOptions =
{ ...options; ...overrides; TimeoutSeconds = 60 }
printn $"{endpoint.Host}:{endpoint.Port}"
printn $"{production.Host}:{production.Port}, timeout {production.TimeoutSeconds}s"
// localhost:5432
// db.example.com:5433, timeout 60s
endpoint hält nur Host und Port; production kombiniert Quellen und explizite Außerkraftsetzungen. Explizite Felder, die nicht im Ziel vorhanden sind, bleiben Fehler.
Ein nicht kommentierter anonymer Datensatz akzeptiert alle beigetragenen Felder. Ein benanntes Ziel muss ableitend sein. Unbekannte Quellen benötigen eigene Anmerkungen, z (source: ClientOptions) . B. für einen Funktionsparameter.
Feldreihenfolge und Außerkraftsetzungen
Beiträge werden von links nach rechts gelesen. Bei einem wiederholten Feldnamen gewinnt der äußerst rechte Beitrag. Die Regel gilt sowohl für Felddeklarationen in Typen als auch für Feldwerte in Ausdrücken.
let laterHost = {| Host = "db.example.com" |}
let corrected: Endpoint = { ...local; ...laterHost; Port = 5433 }
Geben Sie nach einer Typüberschreibung einen Wert des Ersetzungstyps an. Wiederholte explizite Felder, z { Host = "first"; Host = "second" }. B. Fehler.
Für Typdeklarationen wird ein Gewinnfeld an der Position seines Gewinnbeitrags angezeigt. Felder aus einer Quelle behalten ihre Quellreihenfolge bei. Diese Reihenfolge ist für Konstruktoren und Signaturkonformität wichtig.
Auswertung und Kopieren
Spread Source Expressions run once each, in source order, even if a later contribution replaces every field they provide:
let visits = ResizeArray<string>()
let hostFrom source host =
visits.Add source
{| Host = host |}
let selected =
{| ...hostFrom "first" "localhost"
...hostFrom "second" "db.example.com" |}
assert (selected.Host = "db.example.com")
assert (Seq.toList visits = [ "first"; "second" ])
Spreads erstellen einen neuen Datensatz mit Flachfeldkopien und den gleichen Konvertierungen wie explizite Zuordnungen. Veränderbare Objekte, auf die von Feldern verwiesen wird, bleiben freigegeben.
Geschachtelte Feldaktualisierungen funktionieren mit Spreads, wie beim Kopieren und Aktualisieren:
let original = {| Connection = local; Retries = 3 |}
let changed = {| ...original; Connection.Port = 5433 |}
assert (changed.Connection.Port = 5433)
assert (original.Connection.Port = 5432)
Ein späterer Beitrag, um Connection eine frühere geschachtelte Aktualisierung dieses Felds zu ersetzen. Platzieren Sie absichtliche Außerkraftsetzungen nach den Spreads, die sie überschreiben sollten.
Warnungen zu schattierten Feldern
Eine spätere Verbreitung kann versehentlich eine explizite Auswahl rückgängig machen. Der Compiler meldet diese Warnungen standardmäßig:
| Warning | Meaning |
|---|---|
| FS3897 | Ein Feld aus einem Typ verteilt Schatten einer früheren expliziten Felddeklaration. |
| FS3898 | Ein Feld aus einem Ausdruck verteilt Schatten einer früheren expliziten Feldbindung. |
Nehmen Sie Host z. B. { Host = "db.example.com"; ...local } von local, nicht "db.example.com".
Aktivieren Sie für eine Überwachung anderer Überlappungen diese Opt-In-Warnungen:
| Warning | Meaning |
|---|---|
| FS3905 | Ein Typ verteilt schatten ein Feld aus einer früheren Typausbreite. |
| FS3906 | Ein explizites Feld schattiert ein Feld aus einer früheren Ansicht. |
| FS3907 | Ein Ausdruck verteilt schatten ein Feld aus einem früheren Ausdruck. |
<WarnOn>$(WarnOn);3905;3906;3907</WarnOn>
Diese Benachrichtigungen ändern das Verhalten von "Recht am weitesten rechts" nicht.
Darstellung und API-Kompatibilität
Der Typ verteilt die Kopierfeldveränderbarkeit und Attribute auf Feldebene. Sie kopieren keine Attribute auf Typebene; das eigene [<Struct>] Attribut des Ziels bestimmt seine Darstellung. Quelltypargumente müssen die generischen Einschränkungen der Quelle erfüllen, einschließlich Der Einschränkungen für Maßeinheiten.
Important
Verwenden Sie Typ-Spreads nur, wenn die gemeinsame Entwicklung beabsichtigt ist. Eine Änderung des Quellfelds kann die öffentlichen Felder, Konstruktoren, Attribute oder Einschränkungen des Ziels ändern, ohne dass das Ziel bearbeitet wird.
Spreads umgehen keine Barrierefreiheitsprüfungen. Nullfähige Datensätze sind keine gültigen Spreadquellen; Stellen Sie fest, dass ein nullwertebarer Wert nicht null ist, bevor er verwendet wird. Zyklische Abhängigkeiten durch Spreads werden abgelehnt. Gewöhnliche rekursive Datensatzfelder sind nicht nur verboten, weil die Deklaration auch eine Spread verwendet.
Die Typansichten funktionieren in .fsi Dateien. Eine Signatur kann explizite Felder verwenden, während die Implementierung Spreads oder umgekehrt verwendet, vorausgesetzt, die resultierenden Felder und deren Reihenfolge stimmen zu. Anführungszeichen enthalten die aufwendige Datensatzkonstruktion, nicht einen Spreadknoten.
Auswählen von Spreads oder Kopieren und Aktualisieren
Verwenden Sie Kopier- und Aktualisierungsausdrücke für eine Aktualisierung desselben Typs aus einer Quelle. Verwenden Sie Spreads, um Quellen, Projekte zu einem anderen Datensatztyp zu kombinieren oder Felddeklarationen wiederzuverwenden. Kombinieren Sie nicht with denselben Datensatzausdruck....
Spreads gelten nicht für Auflistungen, Objektausdrücke, beliebige .NET Objekte oder C#-Datensätze. Sie stellen keine Datensatzmustersyntax bereit. Datensatzkonstruktoren sind ein separates F#11.2-Feature.