Compartir a través de


Firmas

Un archivo de firma contiene información sobre las firmas públicas de un conjunto de elementos de programa de F#, como tipos, espacios de nombres y módulos. Se puede usar para especificar la accesibilidad de estos elementos de programa.

Observaciones

Para cada archivo de código F#, puede tener un archivo de firma, que es un archivo que tiene el mismo nombre que el archivo de código, pero con la extensión .fsi en lugar de .fs. Los archivos de firma también se pueden agregar a la línea de comandos de compilación si usa directamente la línea de comandos. Para distinguir entre archivos de código y archivos de firma, los archivos de código a veces se conocen como archivos de implementación. En un proyecto, el archivo de firma debe preceder al archivo de código asociado.

Un archivo de firma describe los espacios de nombres, módulos, tipos y miembros del archivo de implementación correspondiente. La información de un archivo de firma se usa para especificar a qué partes del código del archivo de implementación correspondiente se puede tener acceso desde el código fuera del archivo de implementación y a qué partes son internas del archivo de implementación. Los espacios de nombres, módulos y tipos que se incluyen en el archivo de firma deben ser un subconjunto de los espacios de nombres, módulos y tipos que se incluyen en el archivo de implementación. Con algunas excepciones indicadas más adelante en este tema, los elementos de lenguaje que no aparecen en el archivo de firma se consideran privados para el archivo de implementación. Si no se encuentra ningún archivo de firma en el proyecto o en la línea de comandos, se usa la accesibilidad predeterminada.

Para obtener más información sobre la accesibilidad predeterminada, consulte Control de acceso.

En un archivo de firma, no repite la definición de los tipos y las implementaciones de cada método o función. En su lugar, se usa la firma para cada método y función, que actúa como una especificación completa de la funcionalidad implementada por un módulo o fragmento de espacio de nombres. La sintaxis de una firma de tipo es la misma que la que se usa en declaraciones de método abstracto en interfaces y clases abstractas, y también la muestra IntelliSense y el intérprete de F# fsi.exe cuando muestra la entrada compilada correctamente.

Si no hay suficiente información en la firma de tipo para indicar si un tipo está sellado o si es un tipo de interfaz, debe agregar un atributo que indique la naturaleza del tipo al compilador. Los atributos que se usan para este propósito se describen en la tabla siguiente.

Atributo Descripción
[<Sealed>] Para un tipo que no tiene miembros abstractos o que no se deben extender.
[<Interface>] Para un tipo que es una interfaz.

El compilador genera un error si los atributos no son coherentes entre la firma y la declaración en el archivo de implementación.

Use la palabra clave val para crear una firma para un valor o un valor de función. La palabra clave type presenta una firma de tipo.

Puede generar un archivo de firma mediante la --sig opción del compilador. Por lo general, no escribe archivos .fsi manualmente. En su lugar, generará archivos .fsi mediante el compilador, agréguelos al proyecto, si tiene uno y edítelos quitando métodos y funciones a los que no desea que sean accesibles.

Hay varias reglas para las firmas de tipo:

  • Las abreviaturas de tipo de un archivo de implementación no deben coincidir con un tipo sin una abreviatura en un archivo de firma.

  • Los registros y las uniones discriminadas deben exponer todos o ninguno de sus campos y constructores, y el orden de la firma debe coincidir con el orden en el archivo de implementación. Las clases pueden revelar algunos, todos o ninguno de sus campos y métodos en la firma.

  • Las clases y estructuras que tienen constructores deben exponer las declaraciones de sus clases base (la inherits declaración). Además, las clases y estructuras que tienen constructores deben exponer todos sus métodos abstractos y declaraciones de interfaz.

  • Los tipos de interfaz deben revelar todos sus métodos e interfaces.

Las reglas para las firmas de valor son las siguientes:

  • Los modificadores de accesibilidad (public, internal, etc.) y los inline modificadores y mutable de la firma deben coincidir con los de la implementación.

  • El número de parámetros de tipo genérico (inferidos implícitamente o declarados explícitamente) debe coincidir, y los tipos y restricciones de tipo en los parámetros de tipo genérico deben coincidir.

  • Si se usa el Literal atributo , debe aparecer tanto en la firma como en la implementación, y se debe usar el mismo valor literal para ambos.

  • El patrón de parámetros (también conocido como aridad) de firmas e implementaciones debe ser coherente.

  • Si los nombres de parámetro de un archivo de firma difieren del archivo de implementación correspondiente, el nombre del archivo de firma se usará en su lugar, lo que puede provocar problemas al depurar o generar perfiles. Si desea recibir una notificación de estos errores de coincidencia, habilite la advertencia 3218 en el archivo del proyecto o al invocar al compilador (consulte --warnonOpciones del compilador).

En el ejemplo de código siguiente se muestra un ejemplo de un archivo de firma que tiene firmas de espacio de nombres, módulo, valor de función y tipo junto con los atributos adecuados. También muestra el archivo de implementación correspondiente.

// Module1.fsi

namespace Library1
  module Module1 =
    val function1 : int -> int
    type Type1 =
        new : unit -> Type1
        member method1 : unit -> unit
        member method2 : unit -> unit

    [<Sealed>]
    type Type2 =
        new : unit -> Type2
        member method1 : unit -> unit
        member method2 : unit -> unit

    [<Interface>]
    type InterfaceType1 =
        abstract member method1 : int -> int
        abstract member method2 : string -> unit

El código siguiente muestra el archivo de implementación.

namespace Library1

module Module1 =

    let function1 x = x + 1


    type Type1() =
        member type1.method1() =
            printfn "type1.method1"
        member type1.method2() =
            printfn "type1.method2"


    [<Sealed>]
    type Type2() =
        member type2.method1() =
            printfn "type2.method1"
        member type2.method2() =
            printfn "type2.method2"

    [<Interface>]
    type InterfaceType1 =
        abstract member method1 : int -> int
        abstract member method2 : string -> unit

Consulte también