我对 F# 非常陌生,并试图找出在相似但不同的数据对象之间进行转换的最佳方法,同时最大限度地减少代码重复。我正在使用适用于 Xamarin Forms 的 Fabulous F# MVU 框架编写应用程序。
我正在使用 sqlite-net-pcl 进行数据持久性,它在创建数据库表并与该表交互时调用一个对象,并且我创建了一个AuthorObject
:
type AuthorObject() =
[<PrimaryKey>] // sqlite-net-pcl attribute
member val AuthorId = 0 with get, set
member val Username = "" with get, set
member val Token = "" with get, set
Fabulous 使用模型的记录类型,我创建了一个Author
记录类型以在 Fabulous 内部传递:
type Author =
{ AuthorId: int
Username: string
Token: string }
但我还必须与返回AuthorDetailDto
对象的 Web 服务 API 库(用 C# 编写)进行交互。AuthorDetailDto
上面有与上面相同的命名属性,还有更多我不需要担心的。我无法更改 的定义AuthorDetailDto
。
所以目前的限制似乎是 sqlite-net-pcl 需要一个带有成员的对象,Fabulous 需要一个记录类型,而且我有这个AuthorDetailDto
对象来自我无法更改的服务 API 客户端库。我需要在这些类型之间进行转换,我最初希望我能侥幸逃脱:
let convertToObject author = // Was hoping author param here could be generic in some way
let obj = AuthorObject()
obj.AuthorId <- author.AuthorId
obj.Username <- author.Username
obj.Token <- author.Token
obj
let convertToModel (obj: AuthorObject) : Author =
{ AuthorId = obj.AuthorId
Username = obj.Username
Token = obj.Token }
但是由于增加了复杂性AuthorDetailDto
,我发现我现在需要做这样的事情来让编译器满意:
let convertAuthorDetailDtoToObject (dto: AuthorDetailDto) =
let obj = AuthorObject()
obj.AuthorId <- dto.AuthorId
obj.Username <- dto.Username
obj.Token <- dto.Token
obj
let convertAuthorToObject (author: Author) =
let obj = AuthorObject()
obj.AuthorId <- author.AuthorId
obj.Username <- author.Username
obj.Token <- author.Token
obj
let convertToModel (obj: AuthorObject) : Author =
{ AuthorId = obj.AuthorId
Username = obj.Username
Token = obj.Token }
以下是一些源文件:
DomainModels.fs:
namespace MyApp.Mobile
module DomainModels =
type Author =
{ AuthorId: int
Username: string
Token: string }
作者.fs:
namespace MyApp.Mobile.Repository
open SQLite
open Client // Provides AuthorDetailDto.
open MyApp.Mobile.DomainModels
module Author =
type AuthorObject() =
[<PrimaryKey>]
member val AuthorId = 0 with get, set
member val Username = "" with get, set
member val Token = "" with get, set
let convertToObject author =
let obj = AuthorObject()
obj.AuthorId <- author.AuthorId
obj.Username <- author.Username
obj.Token <- author.Token
obj
let convertToModel (obj: AuthorObject) : Author =
{ AuthorId = obj.AuthorId
Username = obj.Username
Token = obj.Token }
let connect dbPath = async {
let db = SQLiteAsyncConnection(SQLiteConnectionString dbPath)
do! db.CreateTableAsync<AuthorObject>() |> Async.AwaitTask |> Async.Ignore
return db
}
let purgeLoggedInAuthor dbPath = async {
let! db = connect dbPath
do! db.ExecuteAsync "DELETE FROM AuthorObject" |> Async.AwaitTask |> Async.Ignore
}
let insertLoggedInAuthor dbPath author = async {
let! db = connect dbPath
do! db.InsertAsync (convertToObject author) |> Async.AwaitTask |> Async.Ignore
}
初始调用如下所示:
insertLoggedInAuthor dbPath loggedInAuthor // loggedInAuthor is an AuthorDetailDto.
该错误是FS0001 This expression was expected to have type 'DomainModels.Author' but here has type 'AuthorDetailDto'
由于在 Author.fs 中引用了这两种类型。
我尝试过使用inline
静态成员约束,并尝试定义接口,但由于Author
需要成为记录类型并且无法更改AuthorDetailDto
,因此这种方法似乎不可行。或者我只是对 F# 不够精通。
对于那些比我更熟悉 F# 的人,解决这种情况以尽量减少代码重复的最佳方法是什么?