F#WsdlService Provider:减少多个提供程序中的重复映射代码

问题描述 投票:1回答:1

我有三个WsdlService类型提供程序,每个提供程序指向同一个WCF服务的不同版本,而底层的MyService.ServiceTypes.Ticket大致相同。我正在使用WsdlService提供程序,因此我们在源代码中唯一的代码是我们从服务中使用的对象。这个项目已经开始替换一个旧项目的片段,其中SvcUtil.exe生成的所有内容都已签入源,即使它未被使用(yuck)。

我有预感code quotationshigher kinded types可能会起作用,因为我想要缩小的功能非常相似。我的用例与我见过的使用F#引用的例子看起来并不相似,我还不了解HKT。

对于3个服务版本,模块VersionMappers中的复制粘贴方法并不是那么糟糕。但是,我们有大约10个不同版本的此服务。我可以再次复制粘贴,但这感觉就像功能语言可以处理的东西。

我的首要问题是:是否有一些F#方法可以将模块VersionMappers中重复的ticketxxToDomain代码减少到类似于CanThisPseudoCodeBeReal模块中的代码,或者我是否在复制粘贴域中将自己逼到了角落?代码报价或HKT是可行的选择吗?

```f#

module DataAccess =
  type Service40 = WsdlService<My40ServiceUrl>
  type Service41 = WsdlService<My41ServiceUrl>
  type Service42 = WsdlService<My42ServiceUrl>

// All the ticketXXToDomain functions look like they can be less copy-paste, but how?
// Still, I think this F# approach is MUCH better than the monolith project we have where WCF SvcUtil.exe
// generate everything for every version and we check that in to source.
module VersionMappers =
  open DataAccess
  module Ticket =
    let ticket40ToDomain (t : Service40.ServiceTypes.Ticket) =
      MyCSharpProject.Pocos.Ticket(
        TicketId = t.TicketId
        // with 10+ other fields
        TicketType = t.TicketType)
    let ticket41ToDomain (t : Service41.ServiceTypes.Ticket) =
      MyCSharpProject.Pocos.Ticket(
        TicketId = t.TicketId
        // with 10+ other fields
        TicketType = t.TicketType)
    let ticket42ToDomain (t : Service42.ServiceTypes.Ticket) =
      MyCSharpProject.Pocos.Ticket(
        TicketId = t.TicketId
        // with 10+ other fields
        TicketType = t.TicketType)

module CanThisPseudoCodeBeReal =
  type ServiceTicket =
    | V40Ticket of Service40.ServiceTypes.Ticket
    | V41Ticket of Service41.ServiceTypes.Ticket
    | V42Ticket of Service42.ServiceTypes.Ticket
  let ticketToDomain (t : 'a when 'a is one case of ServiceTicket) =
    // Now the compiler will hopefully complain if t.SomeField is not on
    // all cases, and I am happy to handle that.
    MyCSharpProject.Pocos.Ticket(
      // I am using fake field names for clarity.
      // every VxxTicket has this field, no warning
      TicketId = t.TicketId,
      // compiler warns that only V40Ticket has this field
      SomeV40Field = t.SomeV40Field,
      // compiler warns that V42Ticket does not have this field
      SomeV40And41Field = t.SomeV40And41Field

    )

```

旁注:ServiceTypes.Ticket对象周围的所有内容(包括检索它们的服务调用)在所有版本的服务中都是相同的,因此我们可以使用一个指向最新版本的WsdlService。我们从源代码中确认了这一点。服务的其他部分并非如此,所以我试图看看是否有某种方法可以在人们抱怨之前减少重复。该项目试图尝试F#和WsdlService提供程序来“扼杀”现有WCF服务外观的一部分。

f# type-providers
1个回答
3
投票

F#知道Statically Resolved Type Parameters允许'编译时泛型'(typesafe duck-typing):

open System

type T1 = { f1: string; f2: int; f3: DateTime }
type T2 = { f2: int; f3: DateTime; f4: double }

type TCommon = { f2: int; f3: DateTime }

let inline toTCommon n = {
    f2 = (^N : (member f2 : int) n)
    f3 = (^N : (member f3 : DateTime) n) }

toTCommon的签名是:

val inline toTCommon :
  n: ^N -> TCommon
    when  ^N : (member get_f2 :  ^N -> int) and
          ^N : (member get_f3 :  ^N -> DateTime)

任何有f2 : intf3 : DateTime的类型都满足于此。

© www.soinside.com 2019 - 2024. All rights reserved.