表达式 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 而不是字符串文本(如 "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 如果实例不可用,则可以使用
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