我正在编写一个适配器类来将 IEnumerable<'T> 映射到 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。
上面的代码有效,但我觉得它有点笨拙,因为我必须为不同的类型(float 等)添加新的专业化。我确实尝试过使用通配符 | :? Option <_> as x -> 在匹配中,但编译器给了我一个“不太通用的警告”,并且代码只会匹配 Option< obj >。
这怎么能写得更惯用呢?我怀疑主动模式可能会起作用,但我从未使用过它们。
对于这个其他功能也是如此:
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