Nameof

Der nameof-Ausdruck generiert eine Zeichenfolgenkonstante, die für fast jedes F#-Konstrukt im Quellcode mit dem Namen im Quellcode übereinstimmt.

Syntax

nameof symbol
nameof<'TGeneric>

Bemerkungen

nameof löst das an diesen Ausdruck übergebene Symbol auf und generiert den Namen dieses Symbols entsprechend der Deklaration im Quellcode. Dies ist in verschiedenen Szenarien nützlich, z. B. bei der Protokollierung, und schützt Ihre Protokollierung vor Änderungen im Quellcode.

let months =
    [
        "January"; "February"; "March"; "April";
        "May"; "June"; "July"; "August"; "September";
        "October"; "November"; "December"
    ]

let lookupMonth month =
    if (month > 12 || month < 1) then
        invalidArg (nameof month) ($"Value passed in was %d{month}.")

    months[month-1]

printfn "%s" (lookupMonth 12)
printfn "%s" (lookupMonth 1)
printfn "%s" (lookupMonth 13)

Die letzte Zeile löst eine Ausnahme aus, und "month" wird in der Fehlermeldung angezeigt.

Sie können einen Namen von fast jedem F#-Konstrukt nehmen:

module M =
    let f x = nameof x

printfn $"{(M.f 12)}"
printfn $"{(nameof M)}"
printfn $"{(nameof M.f)}"

nameof ist keine Funktion erster Klasse und kann nicht als solche verwendet werden. Dies bedeutet, dass sie nicht partiell angewendet werden kann, und Werte können nicht über F#-Pipelineoperatoren in die Pipeline eingefügt werden.

nameof für Operatoren

Operatoren in F# können auf zwei Arten verwendet werden: als Operatortext selbst oder als Symbol, das die kompilierte Form darstellt. nameof für einen Operator generiert den Namen des Operators entsprechend der Deklaration im Quellcode. Um den kompilierten Namen abzurufen, verwenden Sie den kompilierten Namen im Quellcode:

nameof(+) // "+"
nameof op_Addition // "op_Addition"

nameof für Generics

Sie können auch einen Namen eines generischen Typparameters verwenden, aber die Syntax ist anders:

let f<'a> () = nameof<'a>
f() // "a"

nameof<'TGeneric> verwendet den Namen des Symbols entsprechend der Definition im Quellcode, nicht den Namen des Typs, der an einer Aufrufsite ersetzt wird.

Der Grund, warum die Syntax anders ist, ist die Angleichung an andere intrinsische F#-Operatoren wie typeof<> und typedefof<>. Dadurch wird F# konsistent in Bezug auf Operatoren, die auf generische Typen und alles andere im Quellcode angewendet werden.

nameof beim Musterabgleich

Mit dem nameof-Muster können Sie nameof in einem Musterabgleichsausdruck wie folgt verwenden:

let f (str: string) =
    match str with
    | nameof str -> "It's 'str'!"
    | _ -> "It is not 'str'!"

f "str" // matches
f "asdf" // does not match

nameof mit Instanzmembern

F# erfordert eine Instanz, um mit nameof den Namen eines Instanzmembers zu extrahieren. Wenn eine Instanz nicht ohne Weiteres verfügbar ist, kann eine mit Unchecked.defaultof abgerufen werden.

type MyRecord = { MyField: int }
type MyClass() =
    member _.MyProperty = ()
    member _.MyMethod () = ()

nameof Unchecked.defaultof<MyRecord>.MyField   // MyField
nameof Unchecked.defaultof<MyClass>.MyProperty // MyProperty
nameof Unchecked.defaultof<MyClass>.MyMethod   // MyMethod