Nameof

La expresión nameof genera una constante de cadena que coincide con el nombre del origen para casi cualquier construcción de F# en el origen.

Sintaxis

nameof symbol
nameof<'TGeneric>

Comentarios

nameof funciona resolviendo el símbolo pasado y genera el nombre de ese símbolo tal y como se declara en el código fuente. Esto es útil en varios escenarios, como el registro, y protege el registro contra los cambios en el código fuente.

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)

La última línea producirá una excepción y "month" se mostrará en el mensaje de error.

Puede tomar un nombre de casi todas las construcciones de F#:

module M =
    let f x = nameof x

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

nameof no es una función de primera clase y no se puede usar como tal. Esto significa que no se puede aplicar parcialmente y los valores no se pueden canalizar a él a través de operadores de canalización de F#.

Nameof en operadores

Los operadores de F# se pueden usar de dos maneras, como un texto de operador o un símbolo que representa el formulario compilado. nameof en un operador generará el nombre del operador tal y como se declara en el origen. Para obtener el nombre compilado, use el nombre compilado en el origen:

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

Nameof en genéricos

También puede tomar un nombre de un parámetro de tipo genérico, pero la sintaxis es diferente:

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

nameof<'TGeneric> tomará el nombre del símbolo tal y como se define en el origen, no el nombre del tipo sustituido en un sitio de llamada.

La razón por la que la sintaxis es diferente es alinearse con otros operadores intrínsecos de F# como typeof<> y typedefof<>. Esto hace que F# sea coherente con respecto a los operadores que actúan sobre tipos genéricos y cualquier otra cosa en el origen.

Nameof en coincidencia de patrones

El patrón nameof permite usar nameof en una expresión de coincidencia de patrones como esta:

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 con miembros de instancia

F# requiere una instancia para extraer el nombre de un miembro de instancia con nameof. Si una instancia no está fácilmente disponible, se puede obtener una mediante 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