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


Расширения типов (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#)