我一直在寻找一种更简洁的编码方式(如下)。基本上,我需要一种方法来确定一组属性中只有一个不等于其他类型(address
和alternateAddress
是不同类型)上的对应属性。如果5个值中只有一个不匹配,则我要特定的错误,否则我要更一般的错误。
请注意,==
和!=
是自定义中缀运算符,用于不区分大小写的比较。
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
答案 0 :(得分:4)
执行此操作的一种方法是为每个字段定义一个对应的“获取器”列表(获取一条记录并返回字符串的函数)以及相关的错误。为简单起见,我将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!"
值得注意的是,根据您的具体情况,重组代码以使此操作更容易可能是一个好主意-但很难说,如果不了解您的情况。