与.NET API代码交易的关键部分不能正常工作,所以没有办法让这部分代码特别是更地道或更好。然而,函数式编程中的关键是抽象,所以你可以将这个(丑陋的)代码隐藏到一些惯用和可重用的函数中。你可以使用标准的F#列表类型(这对功能数据处理很好)或者seq<'a>
(这是标准的.NET IEnumerable<'a>
),它可以很好地处理其他的.NET库。
取决于你如何在你的代码的其他地方访问数据库,下面可以工作:
// Runs the specified query 'sql' and formats rows using function 'f'
let query sql f =
// Return a sequence of values formatted using function 'f'
seq { use cn = new OleDbConnection(cnstr) // will be disposed
let da = new OleDbDataAdapter(new OleDbCommand(sql, cn))
let ds = new DataSet()
cn.Open()
let i = da.Fill(ds)
// Iterate over rows and format each row
let rowCol = ds.Tables.[0].Rows
for i in 0 .. (rowCount - 1) do
yield f (rowCol.[i]) }
现在你可以使用query
功能大致写你原来的代码是这样的:
let names = query "SELECT * FROM People" (fun row -> row.["LastName"])
printfn "count = %d" (Seq.count names)
for name in names do printfn "%A" name
// Using 'Seq.iter' makes the code maybe nicer
// (but that's a personal preference):
names |> Seq.iter (printfn "%A")
你可以编写的另一个例子是:
// Using records to store the data
type Person { LastName : string; FirstName : string }
let ppl = query "SELECT * FROM People" (fun row ->
{ FirstName = row.["FirstName"]; LastName = row.["LastName"]; })
let johns = ppl |> Seq.filter (fun p -> p.FirstName = "John")
BTW:关于Mau的建议如果有更直接的方法使用语言结构编写代码(例如for
),我不会过分使用高阶函数。上面的iter
的例子很简单,有些人会发现它更具可读性,但没有一般规则...
不知道我明白这个问题。 – BuddyJoe 2010-06-21 13:34:55
他意味着手头的任务(使用.NET库的数据库操作)必然以命令式代码结束,所以F#不会在那里发光。但是,一旦将数据从数据库中取出,它可能非常适合处理数据。 – Mau 2010-06-21 13:38:43
@tyndall Mau是100%正确的。你的代码是100%势在必行的。您可以使用FindReplace将其转换为C#。我认为F#可能不是这里最好的工具。 – Andrey 2010-06-21 13:42:13