I'm writing a adapter class to map IEnumerable<'T> to IDataReader the full source is at https://gist.github.com/jsnape/56f1fb4876974de94238 for reference but I wanted to ask about the best way to write part of it. Namely two functions:
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
This function must return an object but since the values are being passed can be any F# option type which isn't understood by downstream functions such as SqlBulkCopy I need to unpack the option and convert it to a null/DBNull.
The above code works but I feel its a bit clunky since I have to add new specialisations for different types (float etc). I did try using a wildcard | :? Option <_> as x -> in the match but the compiler gave me a 'less generic warning and the code would only match Option< obj >.
How can this be written more idiomatically? I suspect that active patterns might play a part but I've never used them.
Similarly for this other function:
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
I don't care what kind of Option type it is I just want to check against IsNone