F# 在F中添加额外的方法作为类型扩展#

F# 在F中添加额外的方法作为类型扩展#,f#,extension-methods,F#,Extension Methods,我有一个.Net库,它已经实现了.Item方法,例如 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" 在使用此库的代码中,我想添加一个同名的额外方法(因此它是可选扩展名): 以下示例的最后一行未编译: let a = new A(

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

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"
在使用此库的代码中,我想添加一个同名的额外方法(因此它是
可选扩展名
):

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

let a = new A()
a.["good"]    
a.[10]
a.[true]
报告说:

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


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

我认为,问题是因为扩展方法的实现如下(C#):

公共静态类MyModule
{
公共静态无效项(此A、b)
{
//随便
}
}
编译器正在查找
.Item(…)
方法,在原始
库2.A
类中找到它,但无法搜索任何扩展方法

请注意,如果所有
.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"

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

图书馆:

namespace TestLibrary

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

打开测试库
A型
成员m.具有get(a:bool)=“bool”的项
[]
让主argv=
设a=newa()
printfn“%s”(a.get\u项目“a”)
printfn“%s”(a.get\u项目1)
printfn“%s”(a.get\u项为真)
System.Console.ReadLine()|>忽略
0

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

奇怪的是,我在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

内在扩展和可选扩展之间有区别。我的案例是
可选的
。是的,内部扩展被编译到类型本身,就像C#中的
部分
类一样,这可能就是问题的原因。值得注意的是:F#支持扩展属性,但C#不支持。因此,没有一个C#对应物能与他所做的相媲美。我觉得奇怪的是,Intellisense显示了所有三个重载。是的。这让我很困惑。。。
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 
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