During slow time at work I wanted to translate a little DB access framework I coded from C# to F#. This framework uses dynamics and ExpandoObjects extensively. In particular, there's this bit which is giving me headaches:
public static List<dynamic> ToDynamic(this IDataReader reader)
{
dynamic result = new List<dynamic>();
while (reader.Read())
{
var item = new ExpandoObject();
var dc = item as IDictionary<String, object>;
for (int i = 0; i < reader.FieldCount; i++)
{
dc.Add(reader.GetName(i), DBNull.Value.Equals(reader[i]) ? null : reader[i]);
}
result.Add(item);
}
return result;
}
How do you translate this into F#? This is all I could come up with:
let (~~) (x:obj) =
match x with
| :? 't as t -> t
| _ -> null
let rec mapper (reader : SqlDataReader) : list<'Value> =
match reader.Read() with
| false -> []
| true ->
let dc = new ExpandoObject()
let dictionary = ~~dc : Dictionary<string, obj>
[for i in [0 .. reader.FieldCount - 1] do
dictionary.Add(reader.GetName(i), reader.GetValue(i))] @ mapper reader
Except, of course, dictionary comes up null in the cycle. The ~~
was supposed to replace the as
operator from C# but I guess things are not that simple. It might just be a case of Friday, but I really can't see through this.
Because there isn't language support for dynamic, this is slightly more involved in F#. (I recommend reading the docs on DynamicAttribute
.) Here's a translation:
open System.Collections.Generic
open System.Data
open System.Dynamic
open System.Runtime.CompilerServices
[<CompiledName("ToDynamic")>]
let toDynamic (reader: IDataReader) : [<return: Dynamic([|false;true|])>] ResizeArray<obj> =
let results = ResizeArray<obj>()
let rec loop() =
if reader.Read() then
let obj = ExpandoObject() :> IDictionary<_,_>
for i = 0 to reader.FieldCount - 1 do
obj.Add(reader.GetName(i), if reader.IsDBNull(i) then null else reader.[i])
results.Add(obj)
loop()
else results
loop()
If you just want dynamic access to the values in an IDataReader
, a more elegant solution in F# would be to overload the dynamic operator:
let (?) (reader: IDataReader) (name: string) =
match reader.[name] with
| :? DBNull -> Unchecked.defaultof<_>
| value -> unbox value
//Usage: reader?Id
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.