在C#中,我可以使用两个不同的类型参数在一个类上实现两次泛型接口:
interface IFoo<T> { void Foo(T x); }
class Bar : IFoo<int>, IFoo<float>
{
public void Foo(int x) { }
public void Foo(float y) { }
}
我想在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 = ()
但它给出了编译错误:
此类型在不同的通用实例
'IFoo<float>'
和'IFoo<int>'
实现或继承相同的接口。在此版本的F#中不允许这样做。
我在网上找不到任何discussion of this issue。这种用法是不是因为某些原因而不受欢迎?是否有计划在即将发布的F#版本中允许这样做?
答案 0 :(得分:11)
现在我不知道允许这样做的计划。。功能has been planned,至少部分(见注释)在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"); }
}
并从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"
所以这就是F#在这个“边界”的东西上经常发生的事情 - 即使你不能用语言编写同样的东西,F#也可以使用这个东西。
答案 1 :(得分:1)
有一个合理但不优雅的方法,为每个接口创建一个新类型这里是一个消耗来自ESB(nSvcBus)的多个事件的例子,它要求每个事件对应一个已实现的接口。下面的第一个类型包含通用的“处理程序”代码,其他类型只实现接口并调用通用处理程序
type public nSvcBusEvents() =
member this.HandleEvents(msg:IEvent) = ()
//handle messages ie: let json = JsonConvert.SerializeObject(msg)
type public ActionLoggedHandler() =
interface IHandleMessages<Events.ActionLoggedEvent> with
member this.Handle(msg : ActionLoggedEvent) =
nSvcBusEvents().HandleEvents(msg)
type public ActionCompletedHandler() =
interface IHandleMessages<Events.ActionCompletedHandler> with
member this.Handle(msg : ActionCompletedHandler) =
nSvcBusEvents().HandleEvents(msg)
type public ActionFailedHandler() =
interface IHandleMessages<Events.ActionFailedHandler> with
member this.Handle(msg : ActionFailedHandler) =
nSvcBusEvents().HandleEvents(msg)