0

我是 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 语句替换循环体并清理代码。但现在我只是试图通过调试代码并查看数据读取器来确保数据访问正常工作。目前我正在获得一个System.InvalidCastException. 当我在上面注释行指示的点放置一个断点,然后在即时窗口中键入时,reader["name"]我从数据库中获得了一个有效值,所以我知道它正在连接到数据库 ok。但是,如果我尝试将reader["name"](而不是reader.["name"])放入源文件中,我会收到“此值不是函数并且无法应用”消息。

为什么我可以reader["name"]在即时窗口中使用,但不能在我的 fsharp 代码中使用?如何在阅读器中使用字符串索引

更新

按照 Jack P. 的建议,我将代码拆分为单独的行,现在我看到了错误发生的位置:

    let id = reader.["id"]
    let id_unboxed = unbox id // <--- error on this line

id具有object {long}根据调试器的类型。

4

2 回答 2

4

Jack 已经回答了有关在 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

这也应该简化调试,因为您可以进入实现?并查看发生了什么。

于 2013-03-06T03:37:51.367 回答
3

您可以reader["name"]在即时窗口中使用,因为即时窗口使用 C# 语法,而不是 F# 语法。

需要注意的一件事:由于 F# 比 C# 简洁得多,因此在一行中可能会发生很多事情。换句话说,在行上设置断点可能无法帮助您缩小问题范围。在这些情况下,我通常将表达式“扩展”为多行上的多个 let 绑定;这样做可以更轻松地单步执行表达式并找到问题的原因(此时,您可以对原始单行进行更改)。

如果您将项目访问权限拉到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
于 2013-03-06T03:26:15.777 回答