表達式 nameof 會產生字串常數,其符合來源中幾乎任何 F# 建構的來源名稱。
語法
nameof symbol
nameof<'TGeneric>
備註
nameof 可藉由解析傳遞給它的符號,並在原始程式碼中宣告該符號時產生該符號的名稱。 這在各種案例中很有用,例如記錄,並保護您的記錄免於原始程式碼中的變更。
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)
最後一行會擲回例外狀況,並 "month" 會顯示在錯誤訊息中。
您可以取得幾乎每個 F# 建構的名稱:
module M =
let f x = nameof x
printfn $"{(M.f 12)}"
printfn $"{(nameof M)}"
printfn $"{(nameof M.f)}"
nameof 不是一流的函式,因此無法使用。 這表示無法部分套用它,而且值無法透過 F# 管線運算子輸送到其中。
運算子上的 Nameof
F# 中的運算符可以使用兩種方式,做為運算符文字本身,或代表已編譯窗體的符號。
nameof 運算子上會產生運算子的名稱,因為它在來源中宣告。 若要取得編譯的名稱,請使用來源中的已編譯名稱:
nameof(+) // "+"
nameof op_Addition // "op_Addition"
泛型上的 Nameof
您也可以採用泛型類型參數的名稱,但語法不同:
let f<'a> () = nameof<'a>
f() // "a"
nameof<'TGeneric> 會採用來源中所定義的符號名稱,而不是在呼叫月臺取代的類型名稱。
語法不同的原因是要與其他 F# 內建運算元一致,例如 typeof<> 和 typedefof<>。 這可讓 F# 與在泛型型別上運作的運算符以及來源中的其他任何動作保持一致。
模式比對中的 Nameof
此 nameof 模式 可讓您在 nameof 模式比對運算式中使用。 當將字串值與程式碼中的符號名稱進行比對時,這特別有用,可在您重構時提供編譯時安全性和自動更新。
一個實際範例是還原序列化事件或訊息,其中字串值代表類型或案例名稱:
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
使用 nameof instead of string literal like "OrderCreated" 提供數個優點:
- 如果您重新命名區分聯集案例,則型樣會自動更新。
- 編譯器會確保符號存在,以防止拼字錯誤。
- 您的程式碼在重構期間保持一致。
您也可以搭配參數使用 nameof :
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
F# 需要 實例,才能使用 nameof來擷取實例成員的名稱。 如果實例不容易使用,則可以使用 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