Наследование F # с синтаксисом нескольких конструкторов - PullRequest
0 голосов
/ 29 июня 2018

У меня есть этот класс F #

module File1

open System
open System.Collections.Generic

type TimeRangeList<'e>(getter: DateTime * DateTime -> List<'e>, ?maybe_tFrom: DateTime, ?maybe_tTo: DateTime) as this = 
    inherit List<'e>()
    //inherit List<'e>(getter(defaultArg maybe_tTo DateTime.Now, defaultArg maybe_tFrom ((defaultArg maybe_tTo DateTime.Now).AddDays(-1.0))))

    let tTo = defaultArg maybe_tTo DateTime.Now
    let tFrom = defaultArg maybe_tFrom (tTo.AddDays(-1.0))
    do this.AddRange(getter(tFrom, tTo))

Теперь я хочу добавить конструкторы и использовать синтаксис, как в здесь

type TimeRangeList<'e> = 
    inherit List<'e>
    val tFrom: DateTime
    val tTo: DateTime
    new (getter: DateTime * DateTime -> List<'e>, ?maybe_tFrom: DateTime, ?maybe_tTo: DateTime) = {
            inherit List<'e>()
            //inherit List<'e>(defaultArg maybe_tFrom ((defaultArg maybe_tTo DateTime.Now).AddDays(-1.0)), getter(defaultArg maybe_tTo DateTime.Now))

            tTo = defaultArg maybe_tTo DateTime.Now
            tFrom = defaultArg maybe_tFrom (tTo.AddDays(-1.0)) //tTo undefined
            //tFrom = defaultArg maybe_tFrom ((defaultArg maybe_tTo DateTime.Now).AddDays(-1.0))
        }
    do this.AddRange(getter(tFrom, tTo)) //primary constructor required

этот код дает две ошибки:

  1. в 'tFrom = ...' он говорит: «Не определено», в то время как явно объем; В качестве обходного пути я могу повторить вызов defaultArg, как показано в следующая (закомментированная) строка. Есть ли лучший способ?
  2. в последней строке, где вызывается AddRange, жалуется, что вызовы могут выполняться только в первичных конструкторах, что справедливо. Но как мне вызвать необходимый AddRange для инициализации списка? Я пробовал разные варианты, но не смог найти способ. Обходной путь показан в закомментированной строке наследования, но в конце я вызываю defaultArg повторно и излишне; должен быть более ясный и элегантный способ

Ответы [ 2 ]

0 голосов
/ 29 июня 2018

Это синтаксис, который вы ищете:

module File1

open System
open System.Collections.Generic

type TimeRangeList<'e> = 
    inherit List<'e>
    val tFrom: DateTime
    val tTo: DateTime
    new (getter: DateTime * DateTime -> List<'e>, ?maybe_tFrom: DateTime, ?maybe_tTo: DateTime) as this =
        let to_ = defaultArg maybe_tTo DateTime.Now
        let from_ = defaultArg maybe_tFrom (to_.AddDays(-1.0))
        {
            inherit List<'e>()

            tTo = to_
            tFrom = from_
        }
        then
            this.AddRange(getter(this.tFrom, this.tTo))

Ссылки на документацию:

Чтобы пояснить немного, синтаксис { field = value; field2 = value2 } не обязательно должен быть выражением only , найденным в блоке new(), который определяет вторичный конструктор. Это просто должно быть выражение last , то есть возвращаемое выражение. (Здесь, хотя технически блок then является «последним» блоком в конструкторе, его возвращаемое значение (которое должно быть unit) игнорируется, а фактическое возвращаемое значение конструктора является последним выражением не найден в then блоке ). Следовательно, можно безопасно использовать выражения let ранее, чтобы определить значения, которые вы хотите поместить в поля вашего класса, и эти выражения let могут ссылаться друг на друга так же, как в обычном коде. Так что если у вас есть сложный или дорогой расчет, который вам нужно поместить в несколько полей, вы можете сделать что-то вроде:

new () =
    let result = expensiveCalculationIWantToDoOnlyOnce()
    { field1 = result; field2 = result + 1; field3 = result + 2 }
0 голосов
/ 29 июня 2018

Чтобы решить первую проблему, вы должны дать имя текущему объекту: new (...) as this =, а затем получить к нему доступ к переменной this.tTo.AddDays(-1.0).

У меня пока нет решения по второму вопросу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...