2015-01-09 44 views
1

以下代码不会将我的返回值SqlDataReadergetReader正确地转换为调用Seq.unfold时的IDataReader我在做什么错?此表达式预计具有IDataReader类型,但此处具有SqlDataReader类型

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

我根本不知道F#,但是[MSDN](http://msdn.microsoft.com/en-us/library/dd233220.aspx#code-snippet-4)说'当你上传时自动应用上传将参数传递给对象类型上的方法。但是,对于模块中的let-bound函数,上传不是自动的,除非参数类型被声明为灵活类型。所以也许'populateFoo(r:#IDataReader)'会工作吗? – Rhumborl 2015-01-09 21:00:11

回答

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),它会自动上传。这是规范中提到的其中一例。

+0

在阅读14.4.2后,我是否正确理解Seq.unfold是问题的来源,并且是因为它的类型签名'(('' - >('b *'a)option) - >'a - > seq <'b>)'它不能确定''a'的类型是'IDataReader'还是'SqlDataReader'? – 2015-01-09 21:30:41

+0

@CharlesLambert确切地说,它不符合规范中提到的情况。我在答案中加入了一个假设的例子,它可以为你提供帮助。 – Gustavo 2015-01-09 21:43:37

+0

你不需要'展开(a,b:#IDataReader)'? – 2015-01-09 21:45:09

相关问题