Расширения типов (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, но только если модуль, содержащий расширение, открыт, или он присутствует в области по другим причинам.