【问题标题】:Adding extra methods as type extensions in F#在 F# 中添加额外的方法作为类型扩展
【发布时间】:2012-11-05 00:09:26
【问题描述】:

我有一个已经实现 .Item 方法的 .Net 库,例如

namespace Library2
type A() = 
    member m.Item with get(a: string) =   printfn "get a string"
    member m.Item with get(a: int) =   printfn "simple slice"

在使用这个库的代码中,我想添加一个额外的同名方法(因此是optional extensions):

#r @"Library2.dll"
open Library2
type A with
    member m.Item with get(a: bool) =
        printfn "get a bool"

以下示例的最后一行无法编译:

let a = new A()
a.["good"]    
a.[10]
a.[true]

F# doc 说:

扩展方法不能是虚拟或抽象方法。他们能 重载其他同名方法,但编译器给出 在不明确的调用情况下优先使用非扩展方法。

这意味着我不能用相同的类型签名扩展.ToString/.GetHashCode,但这里我使用不同的类型签名。为什么新方法不能扩展?

【问题讨论】:

  • 我觉得奇怪的是 Intellisense 显示了所有三个重载。
  • 是的。这让我很困惑......

标签: f# extension-methods


【解决方案1】:

我认为,问题是由于扩展方法被实现为以下(C#):

public static class MyModule
{
    public static void Item(this A a, bool b)
    {
        // whatever
    }
}

编译器正在寻找.Item(...) 方法,在原来的Library2.A 类中找到它,但没有找到任何扩展方法。

请注意,如果 all .Item(...) 重载是扩展方法,则一切正常:

module Library2 =
    type A() = 
        member m.dummy = ()

open Library2
type A with
    member m.Item with get(a: string) =   printfn "get a string"
    member m.Item with get(a: int) =   printfn "simple slice"
    member m.Item with get(a: bool) = printfn "get a bool"

【讨论】:

【解决方案2】:

这似乎是编译器中的一个错误。扩展方法就在那里,当您放弃索引器附带的漂亮语法糖时,可以调用它,即这有效:

图书馆:

namespace TestLibrary

type A() = 
    member m.Item with get(a: string) = "string"
    member m.Item with get(a: int)    = "int"

主要:

open TestLibrary

type A with
    member m.Item with get(a: bool) = "bool"

[<EntryPoint>]
let main argv = 
    let a = new A()
    printfn "%s" (a.get_Item "a")
    printfn "%s" (a.get_Item 1)
    printfn "%s" (a.get_Item true)
    System.Console.ReadLine() |> ignore
    0 

我的第一个直觉是索引器不能将 unit 作为返回类型,但这并不是问题所在。

【讨论】:

    【解决方案3】:

    奇怪,我在 LinqPad 中创建了一个类似的东西,它按你的预期工作。

    module ModuleA =
    
        type A() = 
            member m.Item with get(a: string) = printfn "get a string"
            member m.Item with get(a: int) = printfn "simple slice"
    
    module ModuleB = 
        open ModuleA
    
        type A with
            member m.Item with get(a: bool) = printfn "get a bool"
    
    open ModuleB
    
    let a = new ModuleA.A()
    a.["good"]    
    a.[10]
    a.[true]
    
    // get a string
    // simple slice
    // get a bool
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-25
      • 1970-01-01
      • 2019-01-21
      • 2014-06-11
      • 1970-01-01
      相关资源
      最近更新 更多