这个表达式应该有IDataReader类型,但这里有类型SqlDataReader

时间:2015-01-09 20:38:43

标签: f# upcasting idatareader

以下代码未在SqlDataReader的调用中将getReader的返回值从IDataReader正确投射到Seq.unfold我做错了什么?

open System.Data
open System.Data.SqlClient
open System.Configuration

type Foo = { id:int; name:string }

let populateFoo (r:IDataReader) =
    let o = r.GetOrdinal
    { id = o "id" |> r.GetInt32; name = o "name" |> r.GetString; }

let iter populateObject (r:IDataReader)  =
    match r.Read() with
    | true -> Some(populateObject r, r)
    | _    -> None

let iterFoo = iter populateFoo

let getReader : IDataReader =
    let cnstr = ConfigurationManager.ConnectionStrings.["db"].ConnectionString
    let cn = new SqlConnection(cnstr)
    let cmd = new SqlCommand("select * from Foo", cn)
    cmd.ExecuteReader()

let foos = Seq.unfold iterFoo getReader

1 个答案:

答案 0 :(得分:3)

除了某些特定情况外,F#不会像C#一样自动向上转播(参见spec,第14.4.2节)。

您必须显式转换表达式:cmd.ExecuteReader() :> IDataReader然后您可以在getReader之后删除类型注释。

或者,您可以让该功能在呼叫站点返回SqlDataReader和向上播放:

let foos = getReader :> IDataReader |> Seq.unfold iterFoo

如果unfold是具有如下签名的类型的静态成员:

type T() =
    static member unfold(a, b:IDataReader) = Seq.unfold a b

您可以直接T.unfold(iterFoo, getReader)直接进行,它会自动向上播放。这是规范中提到的案例之一。