我正在使用对象表达式来实现两个接口。其中一个接口是IDisposable。我希望能够将'use'关键字与此对象表达式的结果一起使用,但是我收到错误:
类型约束不匹配。类型 IConnMan与类型不兼容 IDisposable“IConnMan”类型不是 兼容类型 'IDisposable的'
为什么会出现此错误?
let connectionstring = "context connection=true"
let connman () =
let conn = new SqlConnection(connectionstring)
conn.Open()
{ new IConnMan with
member x.Connect () = conn
member x.Disconnect c = ()
interface IDisposable with
member x.Dispose() =
conn.Close()
conn.Dispose()
}
...
let f() =
use cn = connman() // <-- Error!
答案 0 :(得分:4)
对象表达式只能有一种类型。类型是第一个(主要)实现的接口的类型 - 在您的情况下,这是IconnMan
类型。 F#不允许您使用use
,因为它不会静态地知道connman
函数的结果是IDisposable
。
您可以按相反的顺序在对象表达式中创建接口:
let connman () =
let conn = new SqlConnection(connectionstring)
conn.Open()
{ new IDisposable with
member x.Dispose() =
conn.Close()
conn.Dispose()
interface IConnMan with
member x.Connect () = conn
member x.Disconnect c = () }
然后你可以写use cn = connman()
但是你不能在没有强制转换的情况下使用IConnMan
的函数(这与Desco所做的基本相同)。我不认为这个问题有任何好的解决方案。
您的IConnMan
界面是否可以继承IDisposable
?
答案 1 :(得分:3)
F#规范说:
对象表达式的静态检查如下。 首先,检查ty0到tyn,并且必须都是命名类型。表达式的整体类型是ty0,并且声明等于表达式的初始类型。但是,如果ty0的类型与System.Object等效,并且存在ty1,则整体类型为ty1。
因此您可以使用类型测试和向下转换或更改正在实现的接口序列,因此IDisposable将是第一个
let f() =
use cn = connman() :?> IDisposable