在不同的通用实例中实现相同的接口

Gab*_*iel 16 generics f# interface

在C#中,我可以使用两个不同的类型参数在一个类上实现两次泛型接口:

interface IFoo<T> { void Foo(T x); }

class Bar : IFoo<int>, IFoo<float>
{
    public void Foo(int x) { }
    public void Foo(float y) { }
}
Run Code Online (Sandbox Code Playgroud)

我想在F#中做同样的事情:

type IFoo<'a> = abstract member Foo : 'a -> unit

type Bar() =
    interface IFoo<int> with 
        [<OverloadID("int")>]
        member this.Foo x = ()

    interface IFoo<float> with 
        [<OverloadID("float")>]
        member this.Foo x = ()
Run Code Online (Sandbox Code Playgroud)

但它给出了编译器错误:

这种类型的实现或继承在不同类属实例相同的接口'IFoo<float>''IFoo<int>'.在此版本的F#中不允许这样做.

我在网上找不到关于这个问题的任何讨论.这种用法是不是因为某些原因而不受欢迎?是否有计划在即将发布的F#中允许这样做?

Bri*_*ian 11

现在我不知道允许这个的计划..该功能已经计划好,至少部分(见注释)在F#4.0中实现.

我认为它目前不允许的唯一原因是它实现起来非常重要(特别是使用F#类型推断),并且在实践中很少出现(我只记得一位客户曾经问过这个问题).

鉴于无限的时间和资源,我认为这是允许的(我可以想象这将被添加到该语言的未来版本中),但是现在看起来这似乎不值得支持的功能.(如果您知道强烈的激励案例,请发送邮件至fsbugs@microsoft.com.)

编辑

作为好奇的实验,我写了这个C#:

public interface IG<T>
{
    void F(T x);
}
public class CIG : IG<int>, IG<string>
{
    public void F(int x) { Console.WriteLine("int"); }
    public void F(string x) { Console.WriteLine("str"); }
}
Run Code Online (Sandbox Code Playgroud)

并从F#引用它(带有表明结果的评论)

let cig = new CIG()
let idunno = cig :> IG<_>  // type IG<int>, guess just picks 'first' interface?
let ii = cig :> IG<int>    // works
ii.F(42)                   // prints "int"
let is = cig :> IG<string> // works
is.F("foo")                // prints "str"
Run Code Online (Sandbox Code Playgroud)

所以这就是F#这个"边界"的东西通常会发生的事情 - 即使你不能在语言中编写相同的东西,F#也可以使用这个东西.

  • 那么,F#类型推断如何处理用C#编写的类型呢?至于理由,那么...... ECMA CLI规范定义了各种类别的CLS合规性; 其中一个是"CLS扩展器".其中一个要求是:"能够......实现任何符合CLS标准的接口." (2认同)