【发布时间】:2014-07-19 14:01:30
【问题描述】:
我正在编写一个适配器类来将 IEnumerable 映射到 IDataReader,完整的源代码位于 https://gist.github.com/jsnape/56f1fb4876974de94238 以供参考,但我想询问编写其中一部分的最佳方法。即两个函数:
member this.GetValue(ordinal) =
let value = match enumerator with
| Some e -> getters.[ordinal](e.Current)
| None -> raise (new ObjectDisposedException("EnumerableReader"))
match value with
| :? Option<string> as x -> if x.IsNone then DBNull.Value :> obj else x.Value :> obj
| :? Option<int> as x -> if x.IsNone then DBNull.Value :> obj else x.Value :> obj
| :? Option<decimal> as x -> if x.IsNone then DBNull.Value :> obj else x.Value :> obj
| :? Option<obj> as x -> if x.IsNone then DBNull.Value :> obj else x.Value
| _ -> value
此函数必须返回一个对象,但由于传递的值可以是下游函数(如 SqlBulkCopy)无法理解的任何 F# 选项类型,因此我需要解压缩选项并将其转换为 null/DBNull。
上面的代码有效,但我觉得它有点笨拙,因为我必须为不同的类型(浮点数等)添加新的特化。我确实尝试过使用通配符 | :? Option <_> as x -> 在匹配中,但编译器给了我一个'不太通用的警告,代码只会匹配 Option。
如何写得更惯用?我怀疑活动模式可能会起作用,但我从未使用过它们。
其他功能也类似:
member this.IsDBNull(ordinal) =
match (this :> IDataReader).GetValue(ordinal) with
| null -> true
| :? DBNull -> true
| :? Option<string> as x -> x.IsNone
| :? Option<int> as x -> x.IsNone
| :? Option<decimal> as x -> x.IsNone
| :? Option<obj> as x -> x.IsNone
| _ -> false
我不在乎它是哪种 Option 类型,我只想检查 IsNone
【问题讨论】:
-
我只想在您的
IsDBNull成员中补充一点,您不必检查IsNone,因为None在内部表示为null,并且将与第一种情况匹配.None :> obj |> function null -> printfn "null" | _ -> printfn "something else"将打印“null”。
标签: f# option idatareader