Работа с дополнительными параметрами в методе - PullRequest
1 голос
/ 20 апреля 2020

Предположим, у меня есть метод "m" внутри класса, который имеет несколько необязательных параметров, а именно:

[<AbstractClass;Sealed>]
type API() =
    static member m(?x1,?x2,?x3,?x4,?x5,?x6,?x7,?x8,?x9) = //performs operations and returns a string

Аргументы от x1 до x4 могут быть строками или кортежем списка строк * string. Чтобы справиться с этим, я представил несколько вариантов:

1) Конечный пользователь будет иметь доступ к DU

Плюсы: реализация кода будет чрезвычайно простой

Минусы: это пользователь не всегда хорошо переносит строку внутри конструктора DU, например,

2) Определяет x1 - x4 как obj и обрабатывает возможные случаи внутренне, вызывая исключение в случае неправильного типа

Плюсы: реализация кода была бы чрезвычайно простой, пользователю не нужно использовать конструкторы DU

Минусы: небезопасен (может вызывать исключения), пользователь не может извлечь информацию из сигнатуры метода

3) Перегрузка метода

Плюсы: безопасный тип, пользователю не нужно использовать конструкторы DU

Минусы: реализация и использование (см. вопрос ниже )

Учитывая этот сценарий, мои вопросы:

1) Есть ли здесь четвертый вариант, который я не вижу?

2) Относительно метода 3:

а) Когда я пытался использовать I t, пропустив параметр x1 (в конце концов, он должен быть необязательным), появилась ошибка «уникальная перегрузка не может быть определена». Как мне с этим справиться?

б) В этом примере у меня 8 возможностей. Нужно ли повторять почти один и тот же код 8 раз для реализации перегрузки?

Ответы [ 2 ]

2 голосов
/ 20 апреля 2020

Другой вариант, который вы можете рассмотреть, это использовать именованные аргументы.

[<AbstractClass;Sealed>]
type API() =
    static member m() = ()
    static member m(?localuris, ?remoteuris: string list, ?acl) = ()
    static member m(?localhost: string,?localport,?localscheme) = ()

Вы можете устранить неоднозначность с именами и реализовать минимальное количество перегрузок. Вам нужно будет реализовать метод m(), чтобы компилятор мог выбрать окончательную перегрузку без предоставленных аргументов. Я иногда использую это как эквивалент FP записи с дополнительными полями.

API.m()
API.m(localhost = "127.0.0.1")
API.m(remoteuris = [ "192.168.1.10" ; "192.168.1.11" ])
2 голосов
/ 20 апреля 2020

Относительно метода 3 : я не думаю, что есть простой способ сделать эту работу для всех возможных комбинаций параметров и типов. Вам, вероятно, понадобятся все возможные комбинации членов, что приведет к комбинаторному взрыву. Я думаю, что компилятор сможет разрешить их, только если вы не используете необязательные параметры. Таким образом, вам может понадобиться что-то вроде:

static member m(x1:string) = ..
static member m(x1:string, x2:string) = ..
static member m(x1:string, x2:(string*string) list) = ..
static member m(x1:(string*string) list) = ..

Ваш метод 2 с obj в качестве аргументов будет работать, но, как вы говорите, у него есть очевидный недостаток: он не является безопасным типом.

Относительно альтернативных опций: Я бы, возможно, рассмотрел использование здесь шаблона построителя:

type APIBuilder(...) = 
  member __.x1(v:string) = APIBuilder(...)
  member __.x1(v:(string*string) list) = APIBuilder(...)
  member __.x2(v:string) = APIBuilder(...)
  member __.x2(v:(string*string) list) = APIBuilder(...)

type API() =
  static member m() = APIBuilder()

Класс APIBuilder должен был бы принять все эти параметры в качестве параметров конструктора и выставить какой-нибудь Build метод для фактического создания результирующего объекта. Вы могли бы написать:

API.m().x3("Hi there").x2(["a","Hi there"])

Это не так компактно, как подход с необязательными параметрами, но оно довольно читабельно. Это также хорошо справляется с перегрузкой, потому что вам нужны только две перегрузки методов, которые устанавливают отдельные параметры.

...