2015-01-09 6 views
1

호출에서 다음 코드는 SqlDataReader의 반환 값을 getReader에서 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)에서는'Upcasting이 자동으로 적용됩니다. 인수를 객체 유형의 메소드에 전달합니다. 그러나 모듈에서 let-bound 함수의 경우 매개 변수 유형이 플랙시 블 유형으로 선언되지 않는 한 업 캐스팅은 자동이 아닙니다. 그래서 아마도'populateFoo (r : #IDataReader)'가 작동할까요? – Rhumborl

답변

3

F 번호 일부 특정 시나리오합니다 (spec, 14.4.2 절 참조)를 제외하고는, C# 등의 자동 upcasting을하지 않는다.

표현식을 명시 적으로 캐스팅해야합니다 (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가 문제의 원인이고, 그 때문에 '(('a -> ('b *'a) 옵션) -> 'a -> seq <'b>)''a'의 타입이'IDataReader' 또는'SqlDataReader'인지를 판단 할 수 없습니까? –

+0

@CharlesLambert 정확하게, 그것은 사양에 언급 된 경우에 맞지 않습니다. 나는 그것이 당신을 위해 업 캐스팅을 할 가상의 예제를 답에 추가합니다. – Gustavo

+0

'unfold (a, b : #IDataReader)'할 필요가 없습니까? –