Как определить разницу между двумя типами? - PullRequest
0 голосов
/ 14 февраля 2019

Я искал более краткий способ кодирования этого (ниже).По сути, мне нужен способ определить, не совпадает ли одно из набора свойств с аналогом другого типа (address и alternateAddress - это разные типы).Если только ОДНО из 5 значений не совпадает, то мне нужна конкретная ошибка, в противном случае я хочу более общую ошибку.

Обратите внимание: == и != являются пользовательскими инфиксными операторами, которые мы имеем для caseнечувствительные сравнения.

   open System

   type Errors =
   | InvalidStreet
   | InvalidCity
   | InvalidState
   | InvalidPostalCode
   | InvalidCountry
   | InvalidAddress

   type Address =
       {
           Street: string
           City: string
           Region: string
           PostalCode: string
           Country: string
       }

   type AlternateAddress =
       {
           Street: string
           City: string
           Region: string
           PostalCode: string
           Country: string
       }

   let inline (==) (s1: string) (s2: string) = s1.Equals(s2, StringComparison.CurrentCultureIgnoreCase)
   let inline (!=) s1 s2 = s1 == s2 |> not

   let address = {Address.Street = "123 Main St."; City = "Happytown"; Region = "CA"; PostalCode = "90210"; Country = "USA"}
   let alternateAddress = Some {AlternateAddress.Street = "123 Main"; City = "Happytown"; Region = "CA"; PostalCode = "90210"; Country = "USA"}

   match alternateAddress with
   | Some alternateAddress ->
       if
              address.Street      != alternateAddress.Street
           && address.City        == alternateAddress.City
           && address.Region      == alternateAddress.Region
           && address.PostalCode  == alternateAddress.PostalCode
           && address.Country     == alternateAddress.Country
       then InvalidStreet
       elif
              address.Street      == alternateAddress.Street
           && address.City        != alternateAddress.City
           && address.Region      == alternateAddress.Region
           && address.PostalCode  == alternateAddress.PostalCode
           && address.Country     == alternateAddress.Country
       then InvalidCity
       elif
              address.Street       == alternateAddress.Street
           && address.City         == alternateAddress.City
           && address.Region       != alternateAddress.Region
           && address.PostalCode   == alternateAddress.PostalCode
           && address.Country      == alternateAddress.Country
       then InvalidState
       elif
              address.Street       == alternateAddress.Street
           && address.City         == alternateAddress.City
           && address.Region       == alternateAddress.Region
           && address.PostalCode   != alternateAddress.PostalCode
           && address.Country      == alternateAddress.Country
       then InvalidPostalCode
       elif
              address.Street       == alternateAddress.Street
           && address.City         == alternateAddress.City
           && address.Region       == alternateAddress.Region
           && address.PostalCode   == alternateAddress.PostalCode
           && address.Country      != alternateAddress.Country
       then InvalidCountry
       else InvalidAddress
   | _ -> InvalidAddress

1 Ответ

0 голосов
/ 15 февраля 2019

Один из способов сделать это - определить список соответствующих «получателей» (функций, которые принимают одну из ваших записей и возвращают строку) для каждого из полей вместе с соответствующей ошибкой.Для простоты я сделал alternateAddress необязательным:

let comparers : ((Address -> _) * (AlternateAddress -> _) * _) list = 
  [ (fun x -> x.Street), (fun x -> x.Street), InvalidStreet;
    (fun x -> x.City), (fun x -> x.City), InvalidStreet 
    (fun x -> x.Region), (fun x -> x.Region), InvalidStreet 
    (fun x -> x.PostalCode), (fun x -> x.PostalCode), InvalidStreet 
    (fun x -> x.Country), (fun x -> x.Country), InvalidStreet ]

Теперь вы можете перебрать comparers и использовать первую функцию для получения поля из Address, вторую функцию для получения поляиз AlternateAddress и, если они не совпадают, возвращают третий элемент кортежа, который является ошибкой для сообщения.

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

let errors = comparers |> List.choose (fun (getAddr, getAlt, err) ->
  if getAddr address != getAlt alternateAddress then Some err else None)

Список errors будет пустым, если проблем нет, будет содержать одну ошибку, если была только одна ошибка, или содержать несколько ошибок.:

match errors with
| [] -> printfn "All good!"
| [err] -> printfn "One error: %A" err
| _ -> printfn "Multiple errors!"

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

...