f#中的类型参数化重载

  • 本文关键字:重载 类型参数 f#
  • 更新时间 :
  • 英文 :


当使用Microsoft.SqlServer.TransactSql.ScriptDom进行解析时,访问者的实现通常是这样的:

open Microsoft.SqlServer.TransactSql.ScriptDom
let assembly _ =
let refs = ResizeArray()
refs, {
new TSqlFragmentVisitor() with
override this.Visit(s:CreateAssemblyStatement) = refs.Add(s)
}

每个这样的访问者占用6个LOC,而唯一的区别是类型提示'CreateAssemblyStatement'

所以我试了这个:

let visitor<'T> _ =
let refs = ResizeArray<'T>()
refs, {
new TSqlFragmentVisitor() with
override this.Visit(s:'T) = refs.Add(s)
}
let assemblyVisitor = visitor<CreateAssemblyStatement>
let executeVisitor = visitor<ExecuteStatement>

编译器对非限制类型的抱怨:

error FS3213: The member 'Visit: 'T -> unit' matches multiple overloads of the same method.
Please restrict it to one of the following:
Visit: TSqlFragment -> unit
Visit: StatementList -> unit
...

添加类型约束没有帮助(TSqlFragment是基类):

let visitor<'T when 'T :> TSqlFragment> _ =
let refs = ResizeArray<'T>()
refs, {
new TSqlFragmentVisitor() with
override this.Visit(s:'T) = refs.Add(s)
}

所以我认为这种方法是不可能的,有没有其他优雅的方法来提出这个类型提示?

不幸的是,这是不可能的-而且我想不出一个优雅的解决方案。

问题在于TSqlFramentVisitorVisit方法不是通用的。这是一个重载的Visit方法,有大量的重载(1031根据我的VS工具提示!)这些方法中的每一个在逻辑上都是不同的方法(它们恰好具有相同的名称,但它们也可以具有不同的名称)。

这意味着没有办法编译通用的visitor函数——因为编译器在编译visitor函数时需要决定覆盖哪个Visit方法。不幸的是,它不能这样做——因为只有当它知道方法参数的类型(从1031个方法中选择一个)时,它才能决定这一点。

(另一个问题是,如果有人定义了一个继承自TSqlFragment的新类,这可能需要覆盖一个甚至不存在的方法!)

相关内容

  • 没有找到相关文章

最新更新