Поделиться через


Расширения типов (F#)

Расширения типов позволяют добавлять новые члены в ранее определенный тип объекта.

// Intrinsic extension.
type typename with
   member self-identifier.member-name =
      body
   ...
   [ end ]

// Optional extension.
type typename with
   member self-identifier.member-name =
      body
   ...
   [ end ]

Заметки

Есть две формы расширений типов, имеющие различный синтаксис и поведение. Встроенное расширение — это расширение, содержащееся в том же пространстве имен или модуле (или в том же исходном файле) и в той же сборке (DLL- файле или исполняемом файле), что и расширяемый тип. Дополнительное расширение — это расширение, не содержащееся в исходном модуле, пространстве имен или сборке расширяемого типа. Встроенные расширения типа отображаются при проверке этого типа с помощью отражения, а дополнительные не отображаются. Дополнительное расширение должно содержаться в модуле, и оно присутствует в области, только если содержащий его модуль открыт.

В указанном выше синтаксисе typename представляет расширяемый тип. Любой доступный тип можно расширить, но именем типа должно быть фактическое имя типа, а не его сокращение. В одном определении типа можно задать определения нескольких членов. self-identifier представляет экземпляр вызываемого объекта, как и для обычных членов.

В упрощенном синтаксисе слово end можно опустить.

Члены, определенные в расширениях типов, можно использовать так же, как и обычные члены этих типов класса. Как и другие члены, они могут быть статическими или членами экземпляров. Такие методы также называются методами расширения, свойства — свойствами расширения и т. д. Члены дополнительных расширений при компиляции преобразуются в статические члены, для которых экземпляр объекта неявно передается в первом параметре. Однако они действуют так, будто они являются членами экземпляра или статическими членами, в зависимости от того, как они были объявлены. Неявно заданные члены расширения включаются как члены данного типа, и их можно использовать без ограничений.

Методы расширения могут быть виртуальными или абстрактными. Они могут перегружать другие методы с этим же именем, но в случае неоднозначного вызова компилятор отдает предпочтение методам, не являющимся методами расширения.

Если для одного типа имеется несколько встроенных расширений типа, все их члены должны быть уникальными. В дополнительных расширениях члены различных расширений типов могут иметь одинаковые имена. Ошибки из-за неоднозначности возникают, только если код клиента открывает две различные области, определяющие одинаковые имена членов.

В следующем примере тип, содержащийся в модуле, имеет встроенное расширение типа. Для клиентского кода, находящегося вне модуля, расширение типа выглядит как обычный член типа во всех отношениях.

module MyModule1 =

    // Define a type.
    type MyClass() =
      member this.F() = 100

    // Define type extension.
    type MyClass with
       member this.G() = 200

module MyModule2 =
   let function1 (obj1: MyModule1.MyClass) =
      // Call an ordinary method.
      printfn "%d" (obj1.F())
      // Call the extension method.
      printfn "%d" (obj1.G())

С помощью встроенных расширений типа можно разделить определение типа на несколько разделов. Эта возможность полезна при работе с большими определениями типов. Например, она позволяет хранить код, созданный компилятором, отдельно от пользовательского кода, или группировать код, созданный различными людьми или связанный с различными функциональными возможностями.

В следующем примере представлено дополнительное расширение типа System.Int32, содержащее метод расширения FromString, вызывающий статический член Parse. Метод testFromString показывает, что новый член вызывается так же, как и любой другой член экземпляра.

// Define a new member method FromString on the type Int32.
type System.Int32 with
    member this.FromString( s : string ) =
       System.Int32.Parse(s)

let testFromString str =  
    let mutable i = 0
    // Use the extension method.
    i <- i.FromString(str)
    printfn "%d" i

testFromString "500"

Новый член экземпляра отображается в IntelliSense так же, как и любые другие методы типа Int32, но только если модуль, содержащий расширение, открыт, или он присутствует в области по другим причинам.

См. также

Основные понятия

Члены (F#)

Другие ресурсы

Справочник по языку F#