F# 在不同的泛型实例化中实现相同的接口
在C#中,我可以使用两个不同的类型参数在一个类上实现两次泛型接口:F# 在不同的泛型实例化中实现相同的接口,f#,interface,generics,F#,Interface,Generics,在C#中,我可以使用两个不同的类型参数在一个类上实现两次泛型接口: 接口IFoo{void Foo(tx);} 类栏:IFoo,IFoo { 公共void Foo(int x){} 公共void Foo(float y){} } 我想在F#做同样的事情: 类型IFoo单元 类型栏()= 接口IFoo与 [] 成员this.Foo x=() 接口IFoo与 [] 成员this.Foo x=() 但它给出了一个编译器错误: 此类型在不同的泛型实例化'IFoo'和'IFoo'中实现或继承相同的接口
接口IFoo{void Foo(tx);}
类栏:IFoo,IFoo
{
公共void Foo(int x){}
公共void Foo(float y){}
}
我想在F#做同样的事情:
类型IFoo单元
类型栏()=
接口IFoo与
[]
成员this.Foo x=()
接口IFoo与
[]
成员this.Foo x=()
但它给出了一个编译器错误:
此类型在不同的泛型实例化'IFoo'
和'IFoo'
中实现或继承相同的接口。此版本的F#中不允许这样做
我在网上找不到。是否出于某种原因而不赞成这种使用?有没有计划在即将发布的F#中允许这样做?现在我不知道有没有计划允许这样做。。该功能和至少部分(见注释)在F#4.0中实现
我认为它目前不被允许的唯一原因是它的实现非常繁琐(特别是对于F#type推断),而且在实践中很少出现(我只记得有一位客户询问过这一点)
考虑到无限的时间和资源,我认为这是允许的(我可以想象这会被添加到该语言的未来版本中),但现在看来这似乎不值得支持。(如果你知道一个强有力的激励案例,请发邮件fsbugs@microsoft.com.)
编辑
作为一个好奇的实验,我写了这个C#:
公共接口
{
空隙F(tx);
}
公共类雪茄:IG,IG
{
公共void F(int x){Console.WriteLine(“int”);}
公共void F(字符串x){Console.WriteLine(“str”);}
}
并从F#中引用了它(带有建议结果的注释)
let cig=new cig()
让idunno=cig:>IG//键入IG,猜猜是否只选择“第一个”接口?
设ii=cig:>IG//
ii.F(42)//打印“int”
让is=cig:>IG//起作用
is.F(“foo”)//打印“str”
因此,这就是通常在这个“边界”上发生的事情,F#-F#可以使用这些东西,即使您不能从语言内部编写相同的东西。有一个合理但不优雅的方法,为每个接口创建一个新类型这里是一个从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)
键入public nSvcBusEvents()=
成员this.HandleEvents(msg:IEvent)=()
//处理消息ie:let json=JsonConvert.SerializeObject(msg)
键入public ActionLoggedHandler()=
接口IHandleMessages与
成员this.Handle(msg:ActionLoggedEvent)=
nSvcBusEvents().HandleEvents(msg)
键入public ActionCompletedHandler()=
接口IHandleMessages与
成员this.Handle(msg:ActionCompletedHandler)=
nSvcBusEvents().HandleEvents(msg)
键入public ActionFailedHandler()=
接口IHandleMessages与
成员this.Handle(msg:ActionFailedHandler)=
nSvcBusEvents().HandleEvents(msg)
Er,那么F#类型推断如何处理用C#编写的此类类型呢?至于理由,那么。。。ECMA CLI规范定义了各种类别的CLS合规性;其中之一是“CLS扩展器”。其中一个要求是:“能够……实现任何符合CLS的接口。”要扩展Pavel的评论,如果在C#中定义一个非通用接口I
,它扩展了IG
和IG
,会发生什么?这个接口可以从F#中实现吗?@kvb,不,这个接口不能从F#中实现。这就是处理面向对象的事件处理系统的方式,例如,实现IHandleHere的一个案例:我正在实现一个IDictionary,它也需要迭代,因为为F#4.0 Pull请求计划的ICollectionFeature可以在以下位置找到:
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"); }
}
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"
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)