【问题标题】:Ambiguity on overload resolution between Action and unit -> unit types in F#Action 和 unit -> F# 中的 unit 类型之间的重载决议的歧义
【发布时间】:2012-04-19 00:16:52
【问题描述】:

给定以下片段:

type Foo() =
    static member Test (act : unit -> unit) = act()
    static member Test (act : Action) = Foo.Test act.Invoke

我在最后一行收到一条错误消息:无法根据此程序点之前的类型信息确定方法“测试”的唯一重载。可能需要类型注释。

不幸的是,类型注释(act.Invoke : unit -> unit) 不能解决歧义,我找不到可以修复它的注释。我希望Action 版本是-> 版本的包装器。我的特定用例是定义一个将从 F# 和 C# 调用的类,因此我希望它能够在两种语言中本地工作。

【问题讨论】:

    标签: f#


    【解决方案1】:

    F# 会为您插入到Action 的转换,因此您可以(理论上)使用一种方法。

    type Foo() =
        static member Test (act : Action) = act.Invoke()
    
    Foo.Test (fun () -> ())
    

    我不知道如何强制编译器在Actionunit -> unit 之间进行选择。另外两个选项:

    1. 使Action 重载主要并执行Foo.Test(Action(act))
    2. 将逻辑放在从公共方法调用的第三个函数中

    但我的建议是采用Action 的单一方法。由于转换是自动的,因此互操作在某种意义上是免费的。

    【讨论】:

    • 可能是作弊,但这会将Action 转换为F# 函数:let cvtAct (a:Action) = fun () -> a.Invoke()
    • @JoelMueller:不幸的是,这仍然无助于编译器选择正确的重载。我假设,由于从unit -> unitAction 的自动转换,它无法区分两者。
    • +1,因为Action unit -> unit 代表,这是正确的答案。
    • 您可以使用act.InvokeAction 转换为F# 函数,从而生成unit -> unit 的函数
    • 我应该说:我不知道如何强制编译器在它们之间进行选择。
    【解决方案2】:

    正如 Daniel 所说,您可能可以跳过第一个重载,因为当采用委托的方法应用于 F# 函数值时,F# 会自动插入委托构造函数(请参阅规范的 8.13.6 部分)。

    如果您真的想定义一个与您的示例具有相同表面积的类型,您可以利用 let-bound 函数不包含类型导向转换(只有方法调用才包含)这一事实:

    type Foo() = 
        static let test act : unit = act()
        static member Test act = test act
        static member Test (act : System.Action) = test act.Invoke
    

    但是,这样做并不是很有用,因为如果您尝试从类外部调用第一个重载,您将遇到同样的问题,就像您在尝试定义第二个重载时遇到的那样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多