【问题标题】:Can I use the 'use' keyword with object expressions?我可以在对象表达式中使用“use”关键字吗?
【发布时间】:2011-04-26 11:40:06
【问题描述】:

我正在使用一个对象表达式来实现两个接口。接口之一是 IDisposable。我希望能够在此对象表达式的结果中使用“use”关键字,但出现错误:

类型约束不匹配。方式 IConnMan 与类型不兼容 IDisposable 类型 'IConnMan' 不是 与类型兼容 '一次性'

为什么会出现此错误?

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!

【问题讨论】:

    标签: f#


    【解决方案1】:

    对象表达式只能有一个类型。该类型是第一个(主要)实现接口的类型 - 在您的情况下,这是 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吗?

    【讨论】:

    • 我希望他们为 F# 3.0 解决这个问题。 use 关键字确实应该检查对象是隐式还是显式地实现 IDisposable。就目前而言,use 关键字真的只能用于 C# 中定义的类型(隐式接口实现)?
    • 我会接受你的建议,让 IConnMan 继承 IDisposable。谢谢!
    • @Robert:不,use 关键字适用于任何静态已知可以实现它的类型(例如,在 F# 中声明的实现它的类)。这不依赖于隐式/显式接口实现。但我同意 fixint 这会很好。不幸的是,唯一的选择是允许写入use a = anything,然后动态检查是否anything :? IDisposable
    • @Robert:允许对象表达式(静态地)具有多种类型是另一个问题 - 这需要对 .NET 类型系统进行一些花哨的扩展,所以不太可能(特别是,你会需要一个 IDisposable+IConnMan 类型,这意味着表达式具有 both 类型)。
    • .NET 类型系统的改变真的有必要吗?现在编译器生成实现指定接口的匿名类型,并且可能从某个给定类型继承,并且这个匿名类的静态类型等于主要实现的接口。编译器可能可以像处理用户定义的类一样处理这个类,记住实现的接口的整个列表。
    【解决方案2】:

    F# 规范说:

    对象表达式的静态检查如下。 首先,检查 ty0 到 tyn 并且必须都是命名类型。表达式的整体类型是 ty0 并且被断言等于表达式的初始类型。但是,如果 ty0 的类型等价于 System.Object 并且存在 ty1,则整体类型改为 ty1。

    因此您可以使用类型测试和向下转换或更改正在实现的接口的顺序,以便 IDisposable 将是第一个

    let f() = 
        use cn = connman() :?> IDisposable
    

    【讨论】:

    • 谢谢。我知道我可以将其转换为 IDisposable,但这存在严重的可用性问题。 :)
    猜你喜欢
    • 1970-01-01
    • 2014-12-27
    • 2010-09-29
    • 1970-01-01
    • 2020-06-30
    • 2012-08-24
    • 2012-06-13
    • 1970-01-01
    • 2012-11-27
    相关资源
    最近更新 更多