Собственные идентификаторы класса F#

Все исходники / Язык программирования F# / OS Windows / Desktop / Исходники приложений / Собственные идентификаторы класса F#
Оглавление:
  1. Экземпляры класса
  2. Собственные идентификаторы экземпляров класса
  3. Собственный идентификатор для всего класса
  4. Self Identifier для одного члена класса
  5. Примеры собственных идентификаторов класса
  6. Исходник примеров применения собственных идентификаторов класса

Экземпляры класса

В языке F# собственный идентификатор (self-identifier, идентификатор экземпляра, само-идентификатор) — это имя, представляющее текущий экземпляр класса. Абстрактные примеры экземпляров одного типа класса: общий тип Собака - экземпляры: Дружок, Полкан, Барбос; общий тип Планета - экземпляры: Земля, Марс, Венера.

Примеры создания экземпляров класса:
// Определение типа
type MyClass(number, name) = 
    let count = number
    let title = name

// Создание экземпляров типа
let myclass1 = MyClass(5, "Первый")
let myclass2 = MyClass(10, "Второй")
let myclass3 = MyClass(15, "Третий")

Собственные идентификаторы экземпляров класса

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

Собственные идентификаторы F# похожи на ссылку this текущего экземпляра в языках C#, Kotlin, на скрытый указатель this в классах С++, PHP, на ключевое слово self в языке Python и т.п.

Статические члены класса F# не требуют собственных идентификаторов, поскольку относятся ко всему типу класса, но к отдельному экземпляру.

Собственный идентификатор для всего класса

Self-identifier с областью видимости для всего определения класса объявляется ключевым словом as, следующим после круглых скобок конструктора. Собственный идентификатор для всего класса можно использовать как в конструкторах, так и в теле любого члена класса. Данный идентификатор является опциональным и нет требований определять его обязательно.

Идентификатор экземпляра определяет класс как рекурсивный, и если объявить self-identifier без его использования это вызовет дополнительную проверку во время выполнения при инициализации типов. Язык F# дисциплинирует, но в тоже время разрешает многое, поэтому компилятор при неиспользованном собственном идентификаторе для всего класса выдаст предупреждение, но не ошибку. Использовать self-identifier после первичного конструктора рекомендуется только тогда, когда они действительно необходимы.

Использовать само-идентификаторы в теле первичного конструктора можно только в do-привязках идущих после всех let-привязок первичного конструктора. Собственный идентификатор внутри let-привязки первичного конструктора вызовет исключение:
System.InvalidOperationException: "Инициализация объекта или значения привела к рекурсивному вызову объекта или значения перед его полной инициализацией." Полная инициализация само-идентификатора происходит после выполнения всех let-привязок первичного конструктора.

Само-идентификаторы класса связаны с конструкторами. Для получения доступа к членам класса из дополнительных конструкторов необходимо определить собственный идентификатор для каждого конструктора отдельно.

Примеры программного кода определения собственных идентификаторов с видимостью для всего класса:
type MyClass() as self =
    let space = " "
    do self.M()
    // Если раскомментировать эту строчку возникнет исключение:
    // System.InvalidOperationException
    //let add = 0
    
    // Само-идентификатор для второго конструктора.
    new(number: int) as self2 =
        MyClass()
        then
            self2.M()

    new(name: string) as self3 =
        MyClass()
        then self3.M()

    member x.M() =
        printfn "%s" (x.M1() + space + x.M2() + x.M3())

    member x.M1() = "Hello"

    member x.M2() = "World"

    member x.M3() = "!"

Self Identifier для одного члена класса

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

Пример использования собственного идентификатора с областью видимости только внутри метода:
type MyClass() = 
    let space = " "
    
    member x.M() =
        printfn "%s" (x.M1() + space + x.M2() + x.M3())

    member private x.M1() = "Hello"

    member private x.M2() = "World"

    member private x.M3() = "!"
В случаях, когда само-идентификатор никогда не используется, традиционно принято использовать символ подчеркивания:
type Class() =
    member _.Method() = printfn "Method()"

Примеры собственных идентификаторов класса

Примеры применения само-идентификаторов для классов, свойств и методов Исходник примеров прикреплён внизу страницы.


// ===== Собственные идентификаторы экземпляра класса F# =====

open System

type MyClass(strdate: string) as classId =

    let mutable property = DateTime.Today

    let safeConvertData (str: string) : DateTime =
        try
            // Пытаемся конвертировать строку в дату.
            System.DateTime.Parse(str)

        // В случае исключения примем меры.
        with
        | ex ->
            printfn $"Не корректная дата!"
            // Изменение даты на прошлую не будет выводить
            // показания остатка дней до события.
            DateTime.Today.AddDays(-1)

    do
        // Само-идентификатору экземпляра класса доступны любые члены:
        // закрытые и открытые.
        classId.StringDate <- strdate
        classId.Date <- DateTime.Today.AddDays(1)
        classId.GetDaysBeforeDate()

    // Доступ невозможен! Области действия идентификаторов методов
    // только внутри члена класса
    //w.StringDate <- strdate
    //x.GetBeforeDate()

    // Если раскомментировать эту строку
    // возникнет исключение:
    // System.InvalidOperationException: 
    // "Инициализация объекта или значения привела к рекурсивному 
    // вызову объекта или значения перед его полной инициализацией."
    // do-привязка с использованием собственного идентификатора 
    // класса должна быть последней в определении
    // первичного конструктора.
    //let lastinit = 67

    // Собственный идентификатор метода необходим методу для доступа к другим членам класса.
    member m.StringDate
        with get () = property.ToLongDateString()
        and set (value) = property <- safeConvertData (value)

    member q.Date
        with private get () = property
        and private set (value) = property <- value

    member x.GetDaysBeforeDate() =
        let today = DateTime.Today
        // x.Date доступ к члену класса через само-идентификатор метода.
        let before = (x.Date - today).Days

        if before >= 0 then
            // classId.StringDate доступ к члену класса через само-идентификатор класса.
            printfn $"Осталось дней - %d{before} до даты %s{classId.StringDate}"


// Исполнение кода.
let id = MyClass("23 ноября 2021")

printfn $""
id.StringDate <- "2021.11.22"
id.GetDaysBeforeDate()

printfn $""
id.StringDate <- "2021.11.56"
id.GetDaysBeforeDate()

Скачать исходник

Тема: «Собственные идентификаторы класса F#» Язык программирования F# SelfIdentifier-vs17.zip Размер:1101 КбайтЗагрузки:120