Sdílet prostřednictvím


Nameof

Výraz nameof vytvoří řetězcovou konstantu, která odpovídá názvu ve zdroji pro téměř jakýkoli konstruktor jazyka F# ve zdroji.

Syntaxe

nameof symbol
nameof<'TGeneric>

Poznámky

nameof funguje tak, že přeloží předaný symbol a vytvoří název tohoto symbolu, protože je deklarován ve zdrojovém kódu. To je užitečné v různých scénářích, jako je protokolování, a chrání vaše protokolování před změnami ve zdrojovém kódu.

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)

Poslední řádek vyvolá výjimku a "month" zobrazí se v chybové zprávě.

Název téměř každého konstruktoru jazyka F#:

module M =
    let f x = nameof x

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

nameof není prvotřídní funkce a nelze ji použít. To znamená, že nelze částečně použít a hodnoty do ní nelze vložit prostřednictvím operátorů kanálu F#.

Nameof on operators

Operátory v jazyce F# lze použít dvěma způsoby, jako samotný text operátoru nebo symbol představující kompilovaný formulář. nameof operátor vytvoří název operátoru, protože je deklarován ve zdroji. Pokud chcete získat zkompilovaný název, použijte zkompilovaný název ve zdroji:

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

Nameof on generics

Můžete také použít název parametru obecného typu, ale syntaxe se liší:

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

nameof<'TGeneric> převezme název symbolu definovaný ve zdroji, nikoli název typu nahrazeného v lokalitě volání.

Důvodem, proč se syntaxe liší, je sladit s jinými vnitřními operátory jazyka F# jako typeof<> a typedefof<>. Díky tomu je jazyk F# konzistentní s ohledem na operátory, které fungují na obecných typech a cokoli jiného ve zdroji.

Nameof in pattern matching

Tento nameof vzor umožňuje použít nameof ve výrazu shody vzorů. To je užitečné zejména při porovnávání řetězcových hodnot s názvy symbolů v kódu, které poskytují bezpečnost kompilace a automatické aktualizace při refaktoringu.

Praktickým příkladem je deserializace událostí nebo zpráv, kde řetězcové hodnoty představují názvy typů nebo písmen:

type EventType =
    | OrderCreated
    | OrderShipped
    | OrderDelivered

let handleEvent eventName data =
    match eventName with
    | nameof OrderCreated -> printfn "Processing order creation: %s" data
    | nameof OrderShipped -> printfn "Processing order shipment: %s" data
    | nameof OrderDelivered -> printfn "Processing order delivery: %s" data
    | _ -> printfn "Unknown event type: %s" eventName

handleEvent "OrderCreated" "Order #123" // matches first case

Použití nameof namísto řetězcových literálů, jako "OrderCreated" je několik výhod:

  • Pokud přejmenujete diskriminovaný sjednocovacího případu, vzor se automaticky aktualizuje.
  • Kompilátor zabraňuje překlepům tím, že zajistí, že symbol existuje.
  • Váš kód zůstává během refaktoringu konzistentní.

Můžete také použít nameof s parametry:

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 with instance members

Jazyk F# vyžaduje instanci k extrahování názvu člena instance s nameof. Pokud instance není snadno dostupná, lze ji získat pomocí Unchecked.defaultof.

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