如何使用F#中的IDataReader字符串索引?
我是F#的新手,试着先潜水,然后再做更正式的介绍。我有以下代码:如何使用F#中的IDataReader字符串索引?
3210我计划yield语句来代替循环体和清理的代码。但现在我只是试图通过调试代码和查看数据读取器来确保数据访问的工作。目前我收到System.InvalidCastException
。当我把一个断点通过上面的注释行指示的点,然后在不久的窗户reader["name"]
型我从数据库中获取一个有效的值,所以我知道它连接到数据库确定。但是,如果我尝试将reader["name"]
(而不是reader.["name"]
)放在源文件中,我会得到“此值不是函数并且无法应用”消息。
为什么我可以在即时窗口使用reader["name"]
,但不能在我的fsharp代码中使用?我如何在阅读器上使用string indexing?
更新
继杰克P.的意见,我打出了代码分成几行,现在我看到那里发生的错误:
let id = reader.["id"]
let id_unboxed = unbox id // <--- error on this line
id
有根据的类型object {long}
调试器。
您可以在立即窗口中使用reader["name"]
,因为立即窗口使用C#语法而不是F#语法。
有一点需要注意:由于F#比C#更简洁,因此可以在单行内进行很多操作。换句话说,在线上设置断点可能无助于缩小问题范围。在这些情况下,我通常会将表达式“扩展”为多行上的多个let-binding;这样做可以更容易地逐步通过表达和发现问题(在这一点,你可以做出改变你原有的单行)的原因。
如果您将项目访问和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
杰克已经回答了有关不同的语法在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
这也应该简化调试,你可以进入的?
实施并看看发生了什么。
这很有帮助。 'let id_unboxed = unbox id'这一行有错误。在调试器中查看'id'的类型,它显示'object {long}'。在直接窗口中,'id is long'返回true,而'id is int'则返回false。所以我猜测它与int vs long casting有关。将进一步试验。 – User 2013-03-06 21:39:38
@User如果它是'long',那么你需要将它作为'int64'(F#语法用于'long')。我认为你需要将它解包到正确的类型('int64')*然后*将它转换为一个'int'(如果这是你所需要的) - 你不能直接解开它(这会导致错误,现在重新看到)。 – 2013-03-06 22:04:28
如果我改变我的人类类型使用'int64'而不是'int'它的作品。不知道为什么它只是从数据库拉ID。 – User 2013-03-06 22:10:36