Методы

Метод — это функция, связанная с типом. В объектно-ориентированном программировании методы используются для предоставления и реализации функциональных возможностей и поведения объектов и типов.

Синтаксис

// Instance method definition.
[ attributes ]
member [inline] self-identifier.method-name parameter-list [ : return-type ] =
    method-body

// Static method definition.
[ attributes ]
static member [inline] method-name parameter-list [ : return-type ] =
    method-body

// Abstract method declaration or virtual dispatch slot.
[ attributes ]
abstract member method-name : type-signature

// Virtual method declaration and default implementation.
[ attributes ]
abstract member method-name : type-signature
[ attributes ]
default self-identifier.method-name parameter-list [ : return-type ] =
    method-body

// Override of inherited virtual method.
[ attributes ]
override self-identifier.method-name parameter-list [ : return-type ] =
    method-body

// Optional and DefaultParameterValue attributes on input parameters
[ attributes ]
[ modifier ] member [inline] self-identifier.method-name ([<Optional; DefaultParameterValue( default-value )>] input) [ : return-type ]

Замечания

В предыдущем синтаксисе можно увидеть различные формы объявлений и определений методов. В более длинных телах методов разрыв строки следует знаку равенства (=), а весь текст метода отступен.

Атрибуты можно применять к любому объявлению метода. Они предшествуют синтаксису определения метода и обычно перечислены в отдельной строке. Дополнительные сведения см. в разделе Атрибуты.

Методы можно пометить inline. Сведения о inline см. в статье Встраиваемые функции.

Не встроенные методы можно использовать рекурсивно в типе; Нет необходимости явно использовать rec ключевое слово.

Методы экземпляра

Методы экземпляра объявляются с member ключевое слово и идентификатором себя, за которым следует точка (.) и имя метода и параметры. Как и в let случае с привязками, список параметров может быть шаблоном. Как правило, параметры метода заключены в скобки в форме кортежа, что является способом отображения методов в F# при создании в других языках платформа .NET Framework. Тем не менее, курриемая форма (параметры, разделенные пробелами), также распространена, а другие шаблоны также поддерживаются.

В следующем примере показано определение и использование метода не абстрактного экземпляра.

type SomeType(factor0: int) =
    let factor = factor0
    member this.SomeMethod(a, b, c) = (a + b + c) * factor

    member this.SomeOtherMethod(a, b, c) = this.SomeMethod(a, b, c) * factor

В методах экземпляра не используйте идентификатор самостоятельного кода для доступа к полям, определенным с помощью привязок let. Используйте идентификатор самостоятельно при доступе к другим членам и свойствам.

Статические методы

Ключевое слово static используется для указания того, что метод можно вызывать без экземпляра и не связан с экземпляром объекта. В противном случае методы являются методами экземпляра.

В примере в следующем разделе показаны поля, объявленные с ключевое слово, элементы свойств, объявленные ключевое слово letmember , и статический метод, объявленный ключевое слово static .

В следующем примере показано определение и использование статических методов. Предположим, что эти определения методов находятся в SomeType классе в предыдущем разделе.

static member SomeStaticMethod(a, b, c) =
   (a + b + c)

static member SomeOtherStaticMethod(a, b, c) =
   SomeType.SomeStaticMethod(a, b, c) * 100

Абстрактные и виртуальные методы

Ключевое слово abstract указывает, что метод имеет виртуальный слот диспетчера и может не иметь определения в классе. Виртуальный слот диспетчера — это запись во внутренне поддерживаемой таблице функций, которая используется во время выполнения для поиска вызовов виртуальных функций в объектно-ориентированном типе. Механизм виртуальной диспетчеризации — это механизм, реализующий полиморфизм, важную функцию объектно-ориентированного программирования. Класс, имеющий по крайней мере один абстрактный метод без определения, является абстрактным классом, что означает, что экземпляры этого класса не могут быть созданы. Дополнительные сведения об абстрактных классах см. в разделе "Абстрактные классы".

Объявления абстрактных методов не включают текст метода. Вместо этого имя метода следует двоеточием (:) и сигнатурой типа для метода. Подпись типа метода совпадает с тем, что показано IntelliSense при приостановке указателя мыши на имя метода в редакторе Visual Studio Code, за исключением имен параметров. Подписи типов также отображаются интерпретатором, fsi.exe при интерактивной работе. Сигнатура типа метода формируется путем перечисления типов параметров, а затем возвращаемого типа с соответствующими символами разделителя. Курированные параметры разделены -> по отдельности, а параметры кортежа разделяются *. Возвращаемое значение всегда отделяется от аргументов символом -> . Круглые скобки можно использовать для группировки сложных параметров, таких как когда тип функции является параметром, или указывать, когда кортеж обрабатывается как один параметр, а не как два параметра.

Можно также предоставить определения абстрактных методов по умолчанию, добавив определение в класс и используя default ключевое слово, как показано в блоке синтаксиса в этом разделе. Абстрактный метод, имеющий определение в том же классе, эквивалентен виртуальному методу в других языках платформа .NET Framework. Независимо от того, существует ли определение, abstract ключевое слово создает новый слот диспетчера в таблице виртуальных функций для класса.

Независимо от того, реализует ли базовый класс абстрактные методы, производные классы могут предоставлять реализации абстрактных методов. Чтобы реализовать абстрактный метод в производном классе, определите метод, имеющий то же имя и сигнатуру в производном классе, за исключением использования override или default ключевое слово, и укажите текст метода. Ключевое слово override и default означает точно то же самое. Используйте override , если новый метод переопределяет реализацию базового класса; используется default при создании реализации в том же классе, что и исходное абстрактное объявление. Не используйте abstract ключевое слово в методе, который реализует метод, объявленный абстрактным в базовом классе.

В следующем примере показан абстрактный метод, имеющий реализацию по умолчанию, эквивалентную виртуальному методу Rotate платформа .NET Framework.

type Ellipse(a0: float, b0: float, theta0: float) =
    let mutable axis1 = a0
    let mutable axis2 = b0
    let mutable rotAngle = theta0
    abstract member Rotate: float -> unit
    default this.Rotate(delta: float) = rotAngle <- rotAngle + delta

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

type Circle(radius: float) =
    inherit Ellipse(radius, radius, 0.0)
    // Circles are invariant to rotation, so do nothing.
    override this.Rotate(_) = ()

Перегруженные методы

Перегруженные методы — это методы, имеющие идентичные имена в заданном типе, но имеющие разные аргументы. В F#необязательные аргументы обычно используются вместо перегруженных методов. Однако перегруженные методы разрешены на языке, при условии, что аргументы находятся в форме кортежа, а не в форме курри.

Необязательные аргументы

Начиная с F# 4.1, можно также иметь необязательные аргументы со значением параметра по умолчанию в методах. Это поможет упростить взаимодействие с кодом C#. В следующем примере показан синтаксис:

open System.Runtime.InteropServices
// A class with a method M, which takes in an optional integer argument.
type C() =
    member _.M([<Optional; DefaultParameterValue(12)>] i) = i + 1

Обратите внимание, что значение, переданное для DefaultParameterValue этого типа, должно соответствовать типу входных данных. В приведенном выше примере это .int Попытка передать не целочисленное значение DefaultParameterValue приведет к ошибке компиляции.

Пример: свойства и методы

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

type RectangleXY(x1: float, y1: float, x2: float, y2: float) =
    // Field definitions.
    let height = y2 - y1
    let width = x2 - x1
    let area = height * width
    // Private functions.
    static let maxFloat (x: float) (y: float) = if x >= y then x else y
    static let minFloat (x: float) (y: float) = if x <= y then x else y
    // Properties.
    // Here, "this" is used as the self identifier,
    // but it can be any identifier.
    member this.X1 = x1
    member this.Y1 = y1
    member this.X2 = x2
    member this.Y2 = y2
    // A static method.
    static member intersection(rect1: RectangleXY, rect2: RectangleXY) =
        let x1 = maxFloat rect1.X1 rect2.X1
        let y1 = maxFloat rect1.Y1 rect2.Y1
        let x2 = minFloat rect1.X2 rect2.X2
        let y2 = minFloat rect1.Y2 rect2.Y2

        let result: RectangleXY option =
            if (x2 > x1 && y2 > y1) then
                Some(RectangleXY(x1, y1, x2, y2))
            else
                None

        result

// Test code.
let testIntersection =
    let r1 = RectangleXY(10.0, 10.0, 20.0, 20.0)
    let r2 = RectangleXY(15.0, 15.0, 25.0, 25.0)
    let r3: RectangleXY option = RectangleXY.intersection (r1, r2)

    match r3 with
    | Some(r3) -> printfn "Intersection rectangle: %f %f %f %f" r3.X1 r3.Y1 r3.X2 r3.Y2
    | None -> printfn "No intersection found."

testIntersection

См. также