我是F#的新手并试图先进行潜水,然后再进行更正式的介绍。我有以下代码:
type Person =
{
Id: int
Name: string
}
let GetPeople() =
//seq {
use conn = new SQLiteConnection(connectionString)
use cmd = new SQLiteCommand(sql, conn)
cmd.CommandType <- CommandType.Text
conn.Open()
use reader = cmd.ExecuteReader()
let mutable x = {Id = 1; Name = "Mary"; }
while reader.Read() do
let y = 0
// breakpoint here
x <- {
Id = unbox<int>(reader.["id"])
Name = unbox<string>(reader.["name"])
}
x
//}
let y = GetPeople()
我打算用yield语句替换循环体并清理代码。但是现在我只是想通过调试代码和查看datareader来确保数据访问的工作原理。目前我正在获得System.InvalidCastException
。当我在上面的注释行指示的位置放置一个断点,然后输入立即窗口reader["name"]
时,我从数据库中获得一个有效值,所以我知道它连接到db ok。但是,如果我尝试在源文件中放置reader["name"]
(而不是reader.["name"]
),我会得到“此值不是函数且无法应用”消息。
为什么我可以在即时窗口中使用reader["name"]
但不能在我的fsharp代码中使用?{1}}?如何将string indexing与读者一起使用?
更新
按照Jack P.的建议,我将代码分成不同的行,现在我看到错误发生的地方:
let id = reader.["id"]
let id_unboxed = unbox id // <--- error on this line
根据调试程序, id
的类型为object {long}
。
答案 0 :(得分:4)
杰克已经回答了有关F#和立即窗口或手表中索引的不同语法的问题,所以我会跳过它。
根据我的经验,从数据库读取数据时获取System.InvalidCastException
的最常见原因是reader.["xyz"]
返回的值实际上是DbNull.Value
而不是实际的字符串或整数。将DbNull.Value
转换为整数或字符串将失败(因为它是一个特殊值),因此如果您正在使用可空列,则需要明确检查:
let name = reader.["name"]
let name_unboxed : string =
if name = DbNull.Value then null else unbox name
您可以通过定义?
运算符来使代码更好,该运算符允许您编写reader?name
来执行查找。如果您正在处理空值,您还可以使用reader?name defaultValue
,其定义如下:
let (?) (reader:IDataReader) (name:string) (def:'R) : 'R =
let v = reader.[name]
if Object.Equals(v, DBNull.Value) then def
else unbox v
然后代码变为:
let name = reader?name null
let id = reader?id -1
这也应该简化调试,因为您可以进入?
的实现并看看发生了什么。
答案 1 :(得分:3)
您可以在即时窗口中使用reader["name"]
,因为即时窗口使用C#语法,而不是F#语法。
有一点需要注意:由于F#比C#简洁得多,因此可以在一行内进行很多操作。换句话说,在线上设置断点可能无法帮助您缩小问题范围。在这些情况下,我通常会将表达式“扩展”为多行上的多个let-bindings;这样做可以更容易地逐步执行表达式并找到问题的原因(此时,您可以只更改原始单行)。
如果将项目访问和unbox
调用拉入他们自己的let-bindings会发生什么?例如:
while reader.Read() do
let y = 0
// breakpoint here
let id = reader.["id"]
let id_unboxed : int = unbox id
let name = reader.["name"]
let name_unboxed : string = unbox name
x <- { Id = id_unboxed; Name = name_unboxed; }
x