简体   繁体   English

F#ExpandoObject作为字典

[英]F# ExpandoObject as Dictionary

During slow time at work I wanted to translate a little DB access framework I coded from C# to F#. 在工作缓慢的时候,我想将我编写的一个小数据库访问框架从C#转换为F#。 This framework uses dynamics and ExpandoObjects extensively. 该框架广泛使用动力学和ExpandoObjects。 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#? 您如何将其转换为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. ~~应该代替了C#中的as运算符,但我想事情并不是那么简单。 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#. 因为没有语言支持动态功能,所以F#中涉及的更多。 (I recommend reading the docs on DynamicAttribute .) Here's a translation: (我建议阅读有关DynamicAttribute的文档。)以下是翻译:

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: 如果只想动态访问IDataReader的值,则F#中一个更优雅的解决方案是重载动态运算符:

let (?) (reader: IDataReader) (name: string) = 
  match reader.[name] with
  | :? DBNull -> Unchecked.defaultof<_>
  | value -> unbox value

//Usage: reader?Id

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM