0

MSDNのドキュメントから、Runが実装されている場合、計算式の最後で自動的に呼び出されることを理解しています。次のように述べています。

builder.Run(builder.Delay(fun () -> {| cexpr |}))

計算式に対して生成されます。Run および/または Delay は、ワークフロー ビルダーで定義されていない場合は省略されます。Run が自動的に呼び出されたときに、ReaderBuilder が MyItem オブジェクトのリストを返すことを期待していました。したがって、タイプの不一致エラーが発生する理由がわかりません。エラーは、ここにリストされているコードの最後にある ProcedureBuilder foo 内の return ステートメントによって生成されます。ワークフロービルダーについて私が誤解していることと、私が間違って実装したことを誰か説明してもらえますか?

次のエラーが表示されます。

タイプ「リスト」はタイプ「ReaderBuilder」と互換性がありません

型制約の不一致。タイプ「リスト」はタイプ ReaderBuilder と互換性がありません タイプ「リスト」はタイプ「ReaderBuilder」と互換性がありません

open System
open System.Data
open System.Data.Common
open System.Configuration

let config = ConfigurationManager.ConnectionStrings.Item("db")
let factory = DbProviderFactories.GetFactory(config.ProviderName)

type Direction =
    | In
    | Out
    | Ref
    | Return

type dbType =
    | Int32
    | String of int


type ReaderBuilder(cmd) =
    let mutable items = []
    member x.Foo = 2

    member x.YieldFrom item =
        items <- item::items
        item

    member x.Run item =
        items


type ProcBuilder(procedureName:string) =
    let name = procedureName
    let mutable parameters = []
    let mutable cmd:DbCommand = null
    let mutable data = []

    member x.Command with get() = cmd

    member x.CreateCommand() =
        factory.CreateCommand()
    member x.AddParameter(p:string*dbType*Direction) =
        parameters <- p::parameters

    member x.Bind(v,f) =
        f v

    member x.Reader = ReaderBuilder(cmd)

    member x.Return(rBuilder:ReaderBuilder) =
        data


let (?<-) (builder:ProcBuilder) (prop:string) (value:'t) =
    builder.Command.Parameters.[prop].Value <- value


type MyItem() =
    let mutable _a = 0
    let mutable _b = String.Empty
    let mutable _c = DateTime.Now

    member x.a
        with get() = _a
        and set n = _a <- n
    member x.b
        with get() = _b
        and set n  = _b <- n
    member x.c
        with get() = _c
        and set n = _c <- n


let proc name = ProcBuilder(name)

let (%) (builder:ProcBuilder) (p:string*dbType*Direction) =
    builder.AddParameter(p)
    builder

let (?) (r:DbDataReader) (s:string) = r.GetOrdinal(s)
let foo x y = 
    let foo = proc "foo" % ("x", Int32, In) % ("y", String(15), In)
    foo?x <- x
    foo?y <- y

    foo {
        do! foo?x <- x
        do! foo?y <- y
        return foo.Reader {
            let item = MyItem()
            item.a <- r.GetInt32("a")
            item.b <- r.GetString("b")
            item.c <- r.GetDateTime("c")
            yield! item
        }
    }
4

1 に答える 1

2

あなたの例の問題は、foo.Reader { ... }ブロックに戻り値の型があることですMyItem list(これは型のRunメンバーがReaderBuilder返すものであるため)。ただし、 のReturnメンバーProcBuilderは type の引数を期待していますReaderBuilder

dataフィールドはReaderBuilder常に空のリストになるため、これも怪しいです。Returnおそらく、 ofを代わりにProcBuilder引数を取るように変更したいと思うでしょう。MyItem list

ただし、データベースへのアクセスにカスタム計算ビルダーを使用しても、あまりメリットはないと思います。ある意味で「非標準の計算」を作成していません。代わりに、コマンドを呼び出してデータを読み取るための適切な構文が必要な場合があります。動的演算子を使用すると、計算ビルダーがなくてもこれを非常にエレガントにすることができます。これについては、以前に記事を書きました。

于 2011-05-14T22:01:47.407 に答える