Nameof

Выражение 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 в выражении сопоставления шаблонов следующим образом:

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 с элементами экземпляра

Для извлечения имени члена nameofэкземпляра с помощью F# требуется экземпляр. Если экземпляр недоступен, его можно получить с помощью 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